feat(cart): implement cart editing policy with granular permissions

This commit is contained in:
2026-08-19 10:16:06 -03:00
parent 8659708e1a
commit 2d0664a7c7
13 changed files with 185 additions and 32 deletions

View File

@@ -58,11 +58,13 @@
[subtotal]="cartSubtotal()"
[discount]="cartDiscount()"
[total]="cartTotal()"
[readonly]="!cartEditingEnabled()"
[allowEditing]="
[readonly]="!canModifyCart()"
[allowModify]="canModifyCart()"
[allowUpdateQuantity]="canUpdateCartQuantity()"
[requireEditingMode]="
createdPurchase()?.status === 'created' || createdPurchase()?.status === 'pending_payment'
"
[allowRemove]="false"
[allowDelete]="false"
[persistQuantityChanges]="false"
[editing]="isEditingItems()"
[editingDisabled]="isUpdatingItem() || isPreparingItemEdit()"

View File

@@ -10,6 +10,7 @@ import { CartService } from '../../../../core/services/cart/cart.service';
import { CheckoutService } from '../../../../core/services/checkout.service';
import { CatalogService } from '../../../../core/services/catalog/catalog.service';
import { TenantService } from '../../../../core/services/tenant.service';
import { CartEditingPolicy } from '../../../../core/services/tenant.interface';
import { CheckoutPageComponent } from './checkout-page.component';
describe('CheckoutPageComponent payment validation', () => {
@@ -32,7 +33,12 @@ describe('CheckoutPageComponent payment validation', () => {
let routerStub: { navigate: ReturnType<typeof vi.fn> };
let routeQueryParamMap: ReturnType<typeof convertToParamMap>;
let authUserState: ReturnType<typeof signal>;
let tenantState: ReturnType<typeof signal<{ codigo: string; cart_editing_enabled?: boolean }>>;
let tenantState: ReturnType<
typeof signal<{
codigo: string;
cart_editing_policy?: CartEditingPolicy;
}>
>;
beforeAll(() => {
try {
@@ -87,7 +93,16 @@ describe('CheckoutPageComponent payment validation', () => {
routerStub = { navigate: vi.fn() };
routeQueryParamMap = convertToParamMap({});
authUserState = signal(null);
tenantState = signal({ codigo: 'tenant-test' });
tenantState = signal({
codigo: 'tenant-test',
cart_editing_policy: {
code: 'full',
allow_modify: true,
allow_delete: true,
allow_update_quantity: true,
allow_update_variant: true,
},
});
await TestBed.configureTestingModule({
imports: [CheckoutPageComponent],
@@ -467,12 +482,22 @@ describe('CheckoutPageComponent payment validation', () => {
});
it('does not allow item editing when the tenant disables cart editing', async () => {
tenantState.set({ codigo: 'tenant-test', cart_editing_enabled: false });
tenantState.set({
codigo: 'tenant-test',
cart_editing_policy: {
code: 'disabled',
allow_modify: false,
allow_delete: false,
allow_update_quantity: false,
allow_update_variant: false,
},
});
const { component } = createComponent();
await component.onEditingItemsChange(true);
expect(component.cartEditingEnabled()).toBe(false);
expect(component.canUpdateCartQuantity()).toBe(false);
expect(component.canModifyCart()).toBe(false);
expect(component.isEditingItems()).toBe(false);
expect(checkoutServiceStub.prepareItemEditing).not.toHaveBeenCalled();
});

View File

@@ -79,8 +79,11 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
protected readonly createdPurchase = signal<PurchaseDetailResponse | null>(null);
protected readonly isLoadingPurchase = signal(true);
protected readonly checkoutStepIndex = signal(0);
protected readonly cartEditingEnabled = computed(
() => this.tenantService.tenant()?.cart_editing_enabled ?? true,
protected readonly canUpdateCartQuantity = computed(
() => this.tenantService.tenant()?.cart_editing_policy?.allow_update_quantity ?? false,
);
protected readonly canModifyCart = computed(
() => this.tenantService.tenant()?.cart_editing_policy?.allow_modify ?? false,
);
protected readonly cartSubtotal = computed(() => {
@@ -181,7 +184,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
return;
}
if (editing && !this.cartEditingEnabled()) {
if (editing && !this.canModifyCart()) {
return;
}
@@ -231,7 +234,7 @@ export class CheckoutPageComponent implements OnInit, OnDestroy {
const itemId = event.item.cartItemId;
if (
!this.cartEditingEnabled() ||
!this.canUpdateCartQuantity() ||
!tenant ||
!purchaseId ||
!itemId ||