feat(orders): credit each order to the expert who placed it, as legacy did
Legacy fixed `orders.reagent_id` once, when the order was placed, and its «میزان فروش» summed `customer_id = X OR reagent_id = X`. The app credited orders to the customer's CURRENT referrer and left out an expert's own orders, so 9 of 49 imported experts showed a different figure. - Order.salesAgentId (+ referrerCustomerId for 17 legacy orders whose referrer was not an expert); additive migration, recent app orders backfilled from the customer's referrer - createOrder records the expert at placement time - one shared filter (agent-orders.ts) for the experts list, expert detail, dashboard and the expert app; child orders follow salesAgentId - customer page gets its «میزان فروش» back - import carries orders.reagent_id as is; ex-experts kept as admins keep their profile so their own orders stay linked - reconcile-sales: 1,557 of 1,558 match legacy's own formula; balances unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8c5d971d1f
commit
29084904e9
@@ -0,0 +1,47 @@
|
||||
-- ============================================================================
|
||||
-- Order.salesAgentId / Order.referrerCustomerId — additive, idempotent.
|
||||
--
|
||||
-- Owner ruling 2026-10-08: keep legacy's rule exactly. An order is credited to
|
||||
-- the expert who was the customer's referrer WHEN IT WAS PLACED (legacy
|
||||
-- `orders.reagent_id`, set once at creation), so a customer moving to another
|
||||
-- expert later never changes past sales or commission. The app used to credit
|
||||
-- an order to the customer's CURRENT referrer, which disagreed with legacy for
|
||||
-- 8 of 49 experts on the imported data.
|
||||
--
|
||||
-- No row is deleted and no existing column changes.
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE "Order" ADD COLUMN IF NOT EXISTS "salesAgentId" TEXT;
|
||||
ALTER TABLE "Order" ADD COLUMN IF NOT EXISTS "referrerCustomerId" TEXT;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Order" ADD CONSTRAINT "Order_salesAgentId_fkey"
|
||||
FOREIGN KEY ("salesAgentId") REFERENCES "AdminUser"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "Order" ADD CONSTRAINT "Order_referrerCustomerId_fkey"
|
||||
FOREIGN KEY ("referrerCustomerId") REFERENCES "Customer"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
EXCEPTION WHEN duplicate_object THEN NULL;
|
||||
END $$;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS "Order_salesAgentId_idx" ON "Order"("salesAgentId");
|
||||
CREATE INDEX IF NOT EXISTS "Order_referrerCustomerId_idx" ON "Order"("referrerCustomerId");
|
||||
|
||||
-- Orders placed in the new app before this column existed: the customer's
|
||||
-- referrer today is the best record there is (these are recent). Orders
|
||||
-- brought over from legacy (orderNumber 'H-<id>') are NOT guessed here — the
|
||||
-- import writes their real `orders.reagent_id`.
|
||||
UPDATE "Order" o
|
||||
SET "salesAgentId" = c."referredByAgentId"
|
||||
FROM "Customer" c
|
||||
WHERE c."id" = o."customerId"
|
||||
AND o."salesAgentId" IS NULL
|
||||
AND c."referredByAgentId" IS NOT NULL
|
||||
AND o."orderNumber" NOT LIKE 'H-%';
|
||||
|
||||
COMMENT ON COLUMN "Order"."salesAgentId" IS
|
||||
'Sales expert credited with this order, fixed when it is placed (legacy orders.reagent_id). Never follows a later change of the customer''s referrer.';
|
||||
COMMENT ON COLUMN "Order"."referrerCustomerId" IS
|
||||
'History only: legacy orders.reagent_id when it named a customer who is not a sales expert. Never set for new orders.';
|
||||
@@ -179,6 +179,8 @@ model AdminUser {
|
||||
memberCode String? // legacy mcode
|
||||
|
||||
referredCustomers Customer[] @relation("ReferralAgent")
|
||||
/// Orders credited to this sales expert — see Order.salesAgentId.
|
||||
creditedOrders Order[] @relation("OrderSalesAgent")
|
||||
supervisedWorkshops Workshop[] @relation("WorkshopSupervisor")
|
||||
branchAllocations BranchAllocation[] @relation("AllocationAuthor")
|
||||
postedLedgerEntries LedgerEntry[]
|
||||
@@ -421,6 +423,9 @@ model Customer {
|
||||
/// account (see SalesExpertProfile.tradingCustomerId). Empty for every
|
||||
/// ordinary customer.
|
||||
salesExpertTradingFor SalesExpertProfile? @relation("SalesExpertTradingAccount")
|
||||
/// Legacy orders that named THIS customer as their referrer — see
|
||||
/// Order.referrerCustomerId. History only.
|
||||
referredOrders Order[] @relation("OrderReferrerCustomer")
|
||||
|
||||
// Credit limit + cached ledger balances (source of truth is LedgerEntry; these
|
||||
// are denormalized for fast reads and reconciled by a scheduled job).
|
||||
@@ -736,6 +741,22 @@ model Order {
|
||||
isSuspendedOverCreditLimit Boolean @default(false)
|
||||
deliveredAt DateTime? // setting this is what triggers debt recognition
|
||||
|
||||
/// The sales expert this order is credited to, fixed when it is placed:
|
||||
/// the customer's referring expert AT THAT MOMENT. Legacy `orders.reagent_id`,
|
||||
/// set once at creation (ApiMobileController.php:601) and never moved, so a
|
||||
/// customer changing expert later does not move past sales or commission
|
||||
/// (owner ruling 2026-10-08). «میزان فروش» counts from here, never from the
|
||||
/// customer's current referrer.
|
||||
salesAgentId String?
|
||||
salesAgent AdminUser? @relation("OrderSalesAgent", fields: [salesAgentId], references: [id], onDelete: SetNull)
|
||||
|
||||
/// History only: a legacy order whose `reagent_id` named a customer who is
|
||||
/// not a sales expert (one such customer, 17 orders in 2022). Legacy counted
|
||||
/// those orders in that customer's own «میزان فروش»; this keeps that figure
|
||||
/// exact. Never set for a new order.
|
||||
referrerCustomerId String?
|
||||
referrerCustomer Customer? @relation("OrderReferrerCustomer", fields: [referrerCustomerId], references: [id], onDelete: SetNull)
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -746,6 +767,8 @@ model Order {
|
||||
|
||||
@@index([customerId])
|
||||
@@index([status])
|
||||
@@index([salesAgentId])
|
||||
@@index([referrerCustomerId])
|
||||
}
|
||||
|
||||
model OrderItem {
|
||||
|
||||
Reference in New Issue
Block a user