diff --git a/docs/MODULE_DATA_FLOW.md b/docs/MODULE_DATA_FLOW.md index b7b6d85..fff00fe 100644 --- a/docs/MODULE_DATA_FLOW.md +++ b/docs/MODULE_DATA_FLOW.md @@ -329,7 +329,7 @@ flowchart TD | `asset_code` | `document_series` via `ASSET_{category.code}` | | `asset_name` | Item name (+ `#N` if qty > 1) | | `item_category_id` / `item_subcategory_id` | From item master (optional GRN line override) | -| `location_id` | From PO `shipping_id` (plant or warehouse) | +| `location_id` | From PO `shipping_id` (plant or warehouse); same source as GRN `location_id` | | `vendor_id`, `po_id`, `grn_id`, `grn_item_id` | From GRN | | `purchase_date` | `grn.grn_date` | | `purchase_cost` | `grn_items.rate` | diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6cdc2e4..5b8baf2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -103,7 +103,6 @@ model asset_service_visits { amc_contract_id BigInt? visit_type String @db.VarChar(30) visit_date DateTime @db.Date - visit_number Int? complaint_no String? @db.VarChar(50) complaint_date DateTime? @db.Date complaint_desc String? @@ -335,7 +334,7 @@ model grn { grn_date DateTime @db.Date po_id BigInt vendor_id BigInt - warehouse_id BigInt + location_id BigInt vendor_invoice_no String? @db.VarChar(100) vendor_invoice_date DateTime? @db.Date vendor_invoice_amount Decimal? @db.Decimal(15, 4) @@ -363,13 +362,14 @@ model grn { users_grn_received_byTousers users? @relation("grn_received_byTousers", fields: [received_by], references: [id], onUpdate: NoAction) users_grn_updated_byTousers users? @relation("grn_updated_byTousers", fields: [updated_by], references: [id], onUpdate: NoAction) vendors vendors @relation(fields: [vendor_id], references: [id], onUpdate: NoAction) - warehouse locations @relation("GRNWarehouseLocation", fields: [warehouse_id], references: [id], onUpdate: NoAction) + location locations @relation("GRNLocation", fields: [location_id], references: [id], onUpdate: NoAction) grn_attachments grn_attachments[] grn_items grn_items[] @@index([grn_date], map: "idx_grn_grn_date") @@index([po_id], map: "idx_grn_po_id") @@index([vendor_id], map: "idx_grn_vendor_id") + @@index([location_id], map: "idx_grn_location_id") } model grn_attachments { @@ -609,7 +609,7 @@ model locations { transfers_from asset_transfers[] @relation("TransferFromLocation") transfers_to asset_transfers[] @relation("TransferToLocation") assets_location assets[] @relation("AssetLocation") - grn_warehouse grn[] @relation("GRNWarehouseLocation") + grn_location grn[] @relation("GRNLocation") parent locations? @relation("LocationHierarchy", fields: [parent_id], references: [id], onUpdate: NoAction) children locations[] @relation("LocationHierarchy") po_billing purchase_orders[] @relation("POBillingLocation") diff --git a/scripts/patch-grn-location-bank-primary-drop-visit-number.sql b/scripts/patch-grn-location-bank-primary-drop-visit-number.sql new file mode 100644 index 0000000..0e656ee --- /dev/null +++ b/scripts/patch-grn-location-bank-primary-drop-visit-number.sql @@ -0,0 +1,127 @@ +-- 1) GRN: warehouse_id → location_id (from PO shipping_id) +-- 2) Vendor bank details: only one active primary per vendor +-- 3) asset_service_visits: drop visit_number +-- Idempotent: safe to re-run. + +BEGIN; + +-- --------------------------------------------------------------------------- +-- 1. GRN warehouse_id → location_id +-- --------------------------------------------------------------------------- +DROP VIEW IF EXISTS v_grn CASCADE; + +DO $$ +BEGIN + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' AND table_name = 'grn' AND column_name = 'warehouse_id' + ) AND NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = 'public' AND table_name = 'grn' AND column_name = 'location_id' + ) THEN + ALTER TABLE grn RENAME COLUMN warehouse_id TO location_id; + END IF; +END $$; + +ALTER TABLE grn ADD COLUMN IF NOT EXISTS location_id BIGINT; + +-- Prefer PO shipping_id; fall back to existing location_id for any orphan rows +UPDATE grn g + SET location_id = po.shipping_id + FROM purchase_orders po + WHERE po.id = g.po_id + AND po.shipping_id IS NOT NULL; + +ALTER TABLE grn ALTER COLUMN location_id SET NOT NULL; + +ALTER TABLE grn DROP CONSTRAINT IF EXISTS grn_warehouse_id_fkey; +ALTER TABLE grn DROP CONSTRAINT IF EXISTS grn_location_id_fkey; +ALTER TABLE grn + ADD CONSTRAINT grn_location_id_fkey FOREIGN KEY (location_id) REFERENCES locations(id); + +DROP INDEX IF EXISTS idx_grn_warehouse_id; +CREATE INDEX IF NOT EXISTS idx_grn_location_id ON grn(location_id); + +CREATE VIEW v_grn AS +SELECT + g.*, + po.po_number, + v.vendor_code, + v.vendor_name, + loc.code AS location_code, + loc.name AS location_name, + loc.type AS location_type +FROM grn g +JOIN purchase_orders po ON po.id = g.po_id +JOIN vendors v ON v.id = g.vendor_id +JOIN locations loc ON loc.id = g.location_id +WHERE g.deleted_at IS NULL; + +-- --------------------------------------------------------------------------- +-- 2. Vendor bank: one active primary per vendor +-- --------------------------------------------------------------------------- +-- Demote duplicates (keep lowest id as primary) +WITH ranked AS ( + SELECT + id, + ROW_NUMBER() OVER (PARTITION BY vendor_id ORDER BY id ASC) AS rn + FROM vendor_bank_details + WHERE is_primary = TRUE AND is_active = TRUE +) +UPDATE vendor_bank_details vbd + SET is_primary = FALSE + FROM ranked r + WHERE vbd.id = r.id + AND r.rn > 1; + +DROP INDEX IF EXISTS uq_vendor_bank_one_primary; +CREATE UNIQUE INDEX uq_vendor_bank_one_primary + ON vendor_bank_details (vendor_id) + WHERE is_primary = TRUE AND is_active = TRUE; + +-- --------------------------------------------------------------------------- +-- 3. Drop visit_number from asset_service_visits +-- --------------------------------------------------------------------------- +DROP VIEW IF EXISTS v_asset_next_service CASCADE; + +ALTER TABLE asset_service_visits DROP COLUMN IF EXISTS visit_number; + +CREATE VIEW v_asset_next_service AS +SELECT + a.id AS asset_id, + a.asset_code, + a.asset_name, + ac_cat.name AS category_name, + loc.name AS location_name, + d.name AS department_name, + sv.id AS last_visit_id, + sv.visit_date AS last_service_date, + sv.visit_type AS last_visit_type, + sv.next_service_date, + (sv.next_service_date - CURRENT_DATE) AS days_to_next_service, + CASE + WHEN sv.next_service_date < CURRENT_DATE THEN 'OVERDUE' + WHEN (sv.next_service_date - CURRENT_DATE) <= 7 THEN 'DUE_THIS_WEEK' + WHEN (sv.next_service_date - CURRENT_DATE) <= 30 THEN 'DUE_THIS_MONTH' + ELSE 'UPCOMING' + END AS service_status, + v.vendor_name AS service_vendor, + amc.contract_no AS amc_contract_no, + amc.end_date AS amc_end_date +FROM assets a +JOIN item_categories ac_cat ON ac_cat.id = a.item_category_id +JOIN locations loc ON loc.id = a.location_id +LEFT JOIN departments d ON d.id = a.department_id +JOIN LATERAL ( + SELECT id, visit_date, visit_type, next_service_date, vendor_id + FROM asset_service_visits + WHERE asset_id = a.id AND deleted_at IS NULL AND next_service_date IS NOT NULL + ORDER BY visit_date DESC + LIMIT 1 +) sv ON TRUE +LEFT JOIN vendors v ON v.id = sv.vendor_id +LEFT JOIN asset_amc_contracts amc + ON amc.asset_id = a.id AND amc.is_active = TRUE AND amc.deleted_at IS NULL +WHERE a.deleted_at IS NULL AND a.status NOT IN ('DISPOSED','SCRAPPED'); + +COMMIT; diff --git a/src/docs/assets-routes.yaml b/src/docs/assets-routes.yaml index 95a2072..85c5536 100644 --- a/src/docs/assets-routes.yaml +++ b/src/docs/assets-routes.yaml @@ -207,7 +207,6 @@ components: visit_type: { type: string, enum: [PREVENTIVE, BREAKDOWN, INSPECTION, INSTALLATION, CALIBRATION, OTHER] } visit_date: { type: string, format: date } amc_contract_id: { type: integer, nullable: true } - visit_number: { type: integer, nullable: true } complaint_no: { type: string, example: CMP-001 } complaint_date: { type: string, format: date, nullable: true } complaint_desc: { type: string } @@ -230,7 +229,6 @@ components: visit_type: { type: string, enum: [PREVENTIVE, BREAKDOWN, INSPECTION, INSTALLATION, CALIBRATION, OTHER] } visit_date: { type: string, format: date } amc_contract_id: { type: integer, nullable: true } - visit_number: { type: integer, nullable: true } complaint_no: { type: string } complaint_date: { type: string, format: date, nullable: true } complaint_desc: { type: string } diff --git a/src/docs/grn-routes.yaml b/src/docs/grn-routes.yaml index ecd623c..ca7443c 100644 --- a/src/docs/grn-routes.yaml +++ b/src/docs/grn-routes.yaml @@ -23,11 +23,12 @@ components: item_subcategory_id: { type: integer, nullable: true, example: 1, description: Optional override; defaults from PO item master when omitted } GrnCreateBody: type: object - required: [grn_date, po_id, warehouse_id, items] + required: [grn_date, po_id, items] + description: | + `location_id` is set automatically from the PO `shipping_id` (not accepted in the request body). properties: grn_date: { type: string, format: date, example: '2026-06-18' } po_id: { type: integer, example: 1 } - warehouse_id: { type: integer, example: 1 } vendor_invoice_no: { type: string, example: INV-2026-001 } vendor_invoice_date: { type: string, format: date, nullable: true } vendor_invoice_amount: { type: number, example: 12000 } @@ -45,7 +46,6 @@ components: minProperties: 1 properties: grn_date: { type: string, format: date } - warehouse_id: { type: integer } vendor_invoice_no: { type: string } vendor_invoice_date: { type: string, format: date, nullable: true } vendor_invoice_amount: { type: number } @@ -90,7 +90,7 @@ paths: - { name: status, in: query, schema: { type: string, enum: [POSTED, CANCELLED] } } - { name: po_id, in: query, schema: { type: integer } } - { name: vendor_id, in: query, schema: { type: integer } } - - { name: warehouse_id, in: query, schema: { type: integer } } + - { name: location_id, in: query, schema: { type: integer } } - { name: date_from, in: query, schema: { type: string, format: date } } - { name: date_to, in: query, schema: { type: string, format: date } } responses: @@ -110,7 +110,7 @@ paths: - { name: status, in: query, schema: { type: string, enum: [POSTED, CANCELLED] } } - { name: po_id, in: query, schema: { type: integer } } - { name: vendor_id, in: query, schema: { type: integer } } - - { name: warehouse_id, in: query, schema: { type: integer } } + - { name: location_id, in: query, schema: { type: integer } } - { name: date_from, in: query, schema: { type: string, format: date } } - { name: date_to, in: query, schema: { type: string, format: date } } responses: diff --git a/src/docs/vendors-routes.yaml b/src/docs/vendors-routes.yaml index a9ff8a4..a8f2972 100644 --- a/src/docs/vendors-routes.yaml +++ b/src/docs/vendors-routes.yaml @@ -113,7 +113,10 @@ components: type: string enum: [CURRENT, SAVINGS, OVERDRAFT] example: CURRENT - is_primary: { type: boolean, example: true } + is_primary: + type: boolean + example: true + description: Only one active primary bank account per vendor. Setting true clears primary on others. is_active: { type: boolean, example: true } VendorBankDetailsUpdateBody: type: object @@ -127,7 +130,10 @@ components: account_type: type: string enum: [CURRENT, SAVINGS, OVERDRAFT] - is_primary: { type: boolean, example: true } + is_primary: + type: boolean + example: true + description: Only one active primary bank account per vendor. Setting true clears primary on others. is_active: { type: boolean, example: true } VendorItemMappingsCreateBody: type: object diff --git a/src/modules/assets/assets-service-visits.service.js b/src/modules/assets/assets-service-visits.service.js index b456c8f..c0a9f2f 100644 --- a/src/modules/assets/assets-service-visits.service.js +++ b/src/modules/assets/assets-service-visits.service.js @@ -42,7 +42,6 @@ const buildVisitData = async (payload, assetId) => { amc_contract_id: payload.amc_contract_id ? BigInt(payload.amc_contract_id) : null, visit_type: payload.visit_type, visit_date: toDateOnly(payload.visit_date), - visit_number: payload.visit_number ?? null, complaint_no: payload.complaint_no || null, complaint_date: payload.complaint_date ? toDateOnly(payload.complaint_date) : null, complaint_desc: payload.complaint_desc || null, @@ -125,7 +124,6 @@ const updateServiceVisit = async (assetId, visitId, payload, userId, requestId) payload.amc_contract_id !== undefined ? payload.amc_contract_id : existing.amc_contract_id, visit_type: payload.visit_type ?? existing.visit_type, visit_date: payload.visit_date ?? existing.visit_date, - visit_number: payload.visit_number !== undefined ? payload.visit_number : existing.visit_number, complaint_no: payload.complaint_no !== undefined ? payload.complaint_no : existing.complaint_no, complaint_date: payload.complaint_date !== undefined ? payload.complaint_date : existing.complaint_date, diff --git a/src/modules/assets/assets.validation.js b/src/modules/assets/assets.validation.js index 741326d..722f087 100644 --- a/src/modules/assets/assets.validation.js +++ b/src/modules/assets/assets.validation.js @@ -213,7 +213,6 @@ const serviceVisitSchema = Joi.object({ .required(), visit_date: Joi.date().iso().required(), amc_contract_id: Joi.number().integer().positive().allow(null).optional(), - visit_number: Joi.number().integer().min(1).allow(null).optional(), complaint_no: Joi.string().max(50).allow(null, '').optional(), complaint_date: Joi.date().iso().allow(null).optional(), complaint_desc: Joi.string().allow(null, '').optional(), diff --git a/src/modules/grn/grn.service.js b/src/modules/grn/grn.service.js index f3dea26..b247d8b 100644 --- a/src/modules/grn/grn.service.js +++ b/src/modules/grn/grn.service.js @@ -9,13 +9,13 @@ const { formatDate } = require('../../utils/pdf/helpers/formatDate'); const { getCompanyForDocuments } = require('../settings/settings.service'); const { rowsToCsv } = require('../../utils/csv'); const repository = require('./grn.repository'); -const { assertWarehouse } = require('../../utils/locations'); +const { assertAnyLocation } = require('../../utils/locations'); const { sanitizeAttachment } = require('./grn.attachments.service'); const grnListInclude = { purchase_orders: { select: { id: true, po_number: true, status: true } }, vendors: { select: { id: true, vendor_code: true, vendor_name: true } }, - warehouse: { select: { id: true, code: true, name: true } }, + location: { select: { id: true, code: true, name: true, type: true } }, users_grn_received_byTousers: { select: { id: true, full_name: true } }, users_grn_created_byTousers: { select: { id: true, full_name: true } }, }; @@ -67,11 +67,12 @@ const grnPdfInclude = { }, }, }, - warehouse: { + location: { select: { id: true, code: true, name: true, + type: true, address: true, city: true, state: true, @@ -95,7 +96,7 @@ const sanitizeGrn = (row) => { const { purchase_orders, vendors, - warehouse, + location, users_grn_received_byTousers, users_grn_created_byTousers, users_grn_quality_checked_byTousers, @@ -110,7 +111,7 @@ const sanitizeGrn = (row) => { ...rest, purchase_order: purchase_orders || null, vendor: vendors || null, - warehouse: warehouse || null, + location: location || null, received_by_user: users_grn_received_byTousers || null, created_by_user: users_grn_created_byTousers || null, quality_checked_by_user: users_grn_quality_checked_byTousers || null, @@ -129,7 +130,6 @@ const sanitizeGrn = (row) => { grn_attachments: undefined, purchase_orders: undefined, vendors: undefined, - warehouses: undefined, users_grn_received_byTousers: undefined, users_grn_created_byTousers: undefined, users_grn_quality_checked_byTousers: undefined, @@ -219,11 +219,11 @@ const buildGrnPdfPayload = (grn, company) => { pincode: vendorAddress?.pincode || '', }, warehouse: { - name: grn.warehouse?.name || '-', - address: grn.warehouse?.address || '', - city: grn.warehouse?.city || '', - state: grn.warehouse?.state || '', - pincode: grn.warehouse?.pincode || '', + name: grn.location?.name || '-', + address: grn.location?.address || '', + city: grn.location?.city || '', + state: grn.location?.state || '', + pincode: grn.location?.pincode || '', }, items, generated_at: `${formatDate(new Date(), { style: 'datetime' })} IST`, @@ -388,7 +388,7 @@ const buildHeaderData = (payload, po, userId) => ({ grn_date: toDateOnly(payload.grn_date), po_id: po.id, vendor_id: po.vendor_id, - warehouse_id: BigInt(payload.warehouse_id), + location_id: BigInt(po.shipping_id), vendor_invoice_no: payload.vendor_invoice_no || null, vendor_invoice_date: payload.vendor_invoice_date ? toDateOnly(payload.vendor_invoice_date) : null, vendor_invoice_amount: payload.vendor_invoice_amount ?? null, @@ -402,7 +402,10 @@ const buildHeaderData = (payload, po, userId) => ({ const createGrn = async (payload, userId, requestId) => { const po = await getReceivablePoOrThrow(payload.po_id); - await assertWarehouse(payload.warehouse_id, 'warehouse_id'); + if (!po.shipping_id) { + throw new ApiError(422, 'PO shipping location is required to create GRN'); + } + await assertAnyLocation(po.shipping_id, 'shipping_id'); const { builtItems, assetPlans } = await validateAndBuildItems(po, payload.items); const header = buildHeaderData(payload, po, userId); @@ -436,7 +439,7 @@ const buildGrnsWhere = (query) => ({ ...(query.status ? { status: query.status } : {}), ...(query.po_id ? { po_id: BigInt(query.po_id) } : {}), ...(query.vendor_id ? { vendor_id: BigInt(query.vendor_id) } : {}), - ...(query.warehouse_id ? { warehouse_id: BigInt(query.warehouse_id) } : {}), + ...(query.location_id ? { location_id: BigInt(query.location_id) } : {}), ...(query.search ? { grn_number: { contains: query.search, mode: 'insensitive' } } : {}), ...(query.date_from || query.date_to ? { @@ -493,7 +496,7 @@ const exportGrns = async (query) => { { key: (row) => row.purchase_order?.po_number || '', header: 'PO Number' }, { key: (row) => row.vendor?.vendor_code || '', header: 'Vendor Code' }, { key: (row) => row.vendor?.vendor_name || '', header: 'Vendor Name' }, - { key: (row) => row.warehouse?.name || '', header: 'Warehouse' }, + { key: (row) => row.location?.name || '', header: 'Location' }, { key: 'vendor_invoice_no', header: 'Vendor Invoice No' }, { key: 'vendor_invoice_date', header: 'Vendor Invoice Date', type: 'date' }, { key: 'vendor_invoice_amount', header: 'Vendor Invoice Amount' }, @@ -515,13 +518,8 @@ const updateGrn = async (id, payload, userId, requestId) => { throw new ApiError(409, 'Only POSTED GRN can be updated'); } - if (payload.warehouse_id) { - await assertWarehouse(payload.warehouse_id, 'warehouse_id'); - } - const data = { ...(payload.grn_date !== undefined ? { grn_date: toDateOnly(payload.grn_date) } : {}), - ...(payload.warehouse_id !== undefined ? { warehouse_id: BigInt(payload.warehouse_id) } : {}), ...(payload.vendor_invoice_no !== undefined ? { vendor_invoice_no: payload.vendor_invoice_no || null } : {}), diff --git a/src/modules/grn/grn.validation.js b/src/modules/grn/grn.validation.js index ec6d6ba..3454597 100644 --- a/src/modules/grn/grn.validation.js +++ b/src/modules/grn/grn.validation.js @@ -21,7 +21,6 @@ const grnItemSchema = Joi.object({ const createGrnSchema = Joi.object({ grn_date: Joi.date().iso().required(), po_id: Joi.number().integer().positive().required(), - warehouse_id: Joi.number().integer().positive().required(), vendor_invoice_no: Joi.string().max(100).allow(null, '').optional(), vendor_invoice_date: Joi.date().iso().allow(null).optional(), vendor_invoice_amount: Joi.number().min(0).allow(null).optional(), @@ -36,7 +35,6 @@ const createGrnSchema = Joi.object({ const updateGrnSchema = Joi.object({ grn_date: Joi.date().iso().optional(), - warehouse_id: Joi.number().integer().positive().optional(), vendor_invoice_no: Joi.string().max(100).allow(null, '').optional(), vendor_invoice_date: Joi.date().iso().allow(null).optional(), vendor_invoice_amount: Joi.number().min(0).allow(null).optional(), @@ -57,7 +55,7 @@ const listGrnQuerySchema = Joi.object({ .optional(), po_id: Joi.number().integer().positive().optional(), vendor_id: Joi.number().integer().positive().optional(), - warehouse_id: Joi.number().integer().positive().optional(), + location_id: Joi.number().integer().positive().optional(), date_from: Joi.date().iso().optional(), date_to: Joi.date().iso().optional(), }); diff --git a/src/modules/vendors/vendors.service.js b/src/modules/vendors/vendors.service.js index ebe679c..d1779e9 100644 --- a/src/modules/vendors/vendors.service.js +++ b/src/modules/vendors/vendors.service.js @@ -459,24 +459,44 @@ const listBankDetails = async (vendorId) => { return rows.map(sanitizeBankDetail); }; +const clearOtherPrimaryBankDetails = async (tx, vendorId, exceptId = null) => { + await tx.vendor_bank_details.updateMany({ + where: { + vendor_id: BigInt(vendorId), + is_primary: true, + is_active: true, + ...(exceptId ? { id: { not: BigInt(exceptId) } } : {}), + }, + data: { is_primary: false }, + }); +}; + const createBankDetail = async (vendorId, payload, userId, requestId) => { await getVendorOrThrow(vendorId); - const created = await prisma.vendor_bank_details.create({ - data: { - bank_name: payload.bank_name, - branch: payload.branch ?? null, - account_number: encrypt(payload.account_number), - account_number_index: blindIndex(payload.account_number), - ifsc: payload.ifsc, - account_holder_name: payload.account_holder_name, - account_type: payload.account_type ?? 'CURRENT', - is_primary: payload.is_primary ?? false, - is_active: payload.is_active ?? true, - vendor_id: BigInt(vendorId), - created_by: userId ? BigInt(userId) : null, - updated_by: userId ? BigInt(userId) : null, - }, + const isPrimary = payload.is_primary ?? false; + + const created = await prisma.$transaction(async (tx) => { + if (isPrimary) { + await clearOtherPrimaryBankDetails(tx, vendorId); + } + + return tx.vendor_bank_details.create({ + data: { + bank_name: payload.bank_name, + branch: payload.branch ?? null, + account_number: encrypt(payload.account_number), + account_number_index: blindIndex(payload.account_number), + ifsc: payload.ifsc, + account_holder_name: payload.account_holder_name, + account_type: payload.account_type ?? 'CURRENT', + is_primary: isPrimary, + is_active: payload.is_active ?? true, + vendor_id: BigInt(vendorId), + created_by: userId ? BigInt(userId) : null, + updated_by: userId ? BigInt(userId) : null, + }, + }); }); await auditLog({ @@ -513,9 +533,15 @@ const updateBankDetail = async (vendorId, bankDetailId, payload, userId, request data.account_number_index = blindIndex(payload.account_number); } - const updated = await prisma.vendor_bank_details.update({ - where: { id: BigInt(bankDetailId) }, - data, + const updated = await prisma.$transaction(async (tx) => { + if (payload.is_primary === true) { + await clearOtherPrimaryBankDetails(tx, vendorId, bankDetailId); + } + + return tx.vendor_bank_details.update({ + where: { id: BigInt(bankDetailId) }, + data, + }); }); await auditLog({