| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- import assert from 'node:assert/strict'
- import test from 'node:test'
- import { readFileSync } from 'node:fs'
- import { parse } from '@vue/compiler-sfc'
- import ts from 'typescript'
- import { ref, nextTick } from 'vue'
- import * as stops from '../src/utils/pl-plan-stop-form'
- import * as persistence from '../src/views/m/pl/plan/mobilePlanPersistence'
- // Evaluate current working-tree handlers, with only external APIs/UI services stubbed.
- const source = parse(
- readFileSync(
- new URL('../src/components/business/pl-plan-form-dialog/index.vue', import.meta.url),
- 'utf8'
- )
- ).descriptor.scriptSetup!.content
- const tree = ts.createSourceFile('form.ts', source, ts.ScriptTarget.Latest, true)
- const names = [
- 'loadPlanForEdit',
- 'loadPlanForCopy',
- 'applyStopsFromPlan',
- 'enrichStopFormsDisplayFromPlanProducts',
- 'bootstrapStopsFromPlanProducts',
- 'mirrorPlanProductsFromLoad',
- 'mapPlanProductToFormRow',
- 'mapPlanProductToCopyFormRow',
- 'mapProductsToSubmitPayload',
- 'buildPlanCommonPayload',
- 'handleSubmit'
- ]
- const code = names
- .map((name) => {
- const node = tree.statements.find(
- (node) => ts.isFunctionDeclaration(node) && node.name?.text === name
- )
- assert.ok(node, name)
- return node.getText(tree)
- })
- .join('\n')
- const clone = (value: any) => JSON.parse(JSON.stringify(value))
- const line = {
- productId: 'sku',
- productNo: 'SKU',
- productName: '产品',
- unit: '吨',
- packageSpec: '桶',
- model: 'M',
- planQty: 5,
- quantity: 5
- }
- function harness(mobile: boolean) {
- const noop = () => {},
- yes = () => true,
- identity = async (rows: any[]) => rows
- let saved: any = {
- id: 'plan',
- mobileProductMetaVersion: 1,
- products: [{ ...line, id: 'pp' }],
- load: { id: 'load', products: [{ ...line, id: 'lp', planProductId: 'pp' }] },
- deliveries: [{ id: 'delivery', seq: 1, products: [{ ...line, id: 'dp', planProductId: 'pp' }] }]
- }
- const writes: any[] = [],
- events: any[] = []
- const b: any = {
- ...stops,
- ...persistence,
- nextTick,
- isPageVariant: ref(mobile),
- props: { planId: 'plan' },
- isEdit: ref(true),
- pageReady: ref(true),
- pageLoadGeneration: 1,
- assertPageLoadCurrent: noop,
- isPageLoadCurrent: yes,
- isPageSubmitCurrent: yes,
- suppressAddressMutex: ref(false),
- suppressStopProductSync: ref(false),
- stopFormsReady: ref(false),
- formData: { products: [] },
- loadForm: ref(stops.createEmptyLoadForm()),
- deliveryForms: ref([]),
- resetForm: noop,
- validateLoadedPagePlan: noop,
- formatDate: () => '',
- todayYmd: () => '2026-10-27',
- resolveCurrentUserId: () => 'u',
- resolveCurrentUserName: () => '',
- syncCommittedPartyIds: noop,
- loadedTransportStatus: ref(''),
- loadedFollowStatus: ref(''),
- loadedPlanSnapshot: ref(null),
- enrichPlanProductsHazardFromCrm: identity,
- enrichPlanProductLinesAlias: identity,
- freightCalc: { resetFreightCalc: noop },
- restoreFreightFromTransport: noop,
- selectedDriverId: ref(''),
- selectedEscortId: ref(''),
- vehicleBundle: ref(null),
- syncSelectedCustomerOptions: noop,
- reapplyStopDibangByVehiclePlate: noop,
- prepareLineAliasAndBrandForSubmit: noop,
- resolveLineProductName: (name: string) => name,
- buildTransportBlock: () => undefined,
- mobileMetadata: { ready: yes },
- mobileSavedPlanId: ref(''),
- mobileCreateUncertain: ref(false),
- submitLoading: ref(false),
- basicFormRef: ref({ validate: async () => true }),
- validateBusinessRules: yes,
- prefetchStopContractProducts: noop,
- validateSingleContractPerStop: yes,
- validateContractPackageSpecs: yes,
- validateStopContractsRequired: yes,
- pickBxData: (x: any) => x,
- showPlanSaveWarnings: noop,
- ElMessage: { warning: noop, error: noop, success: noop },
- innerVisible: ref(true),
- emit: (...args: any[]) => events.push(args),
- planApi: {
- get: async () => clone(saved),
- update: async (_id: string, payload: any) => {
- writes.push(clone(payload))
- // Server returns generated identities for genuinely new rows.
- saved = { ...clone(payload), id: 'plan', mobileProductMetaVersion: 1 }
- saved.products.forEach((row: any, i: number) => {
- row.id ||= `pp-new-${i}`
- })
- const resolve = (row: any) =>
- saved.products.find((pp: any) => pp.clientKey === row.planProductClientKey)?.id ||
- row.planProductId
- saved.load.id ||= 'load-new'
- saved.load.products.forEach((row: any, i: number) => {
- row.id ||= `lp-new-${i}`
- row.planProductId = resolve(row)
- })
- saved.deliveries.forEach((stop: any, i: number) => {
- stop.id ||= `delivery-new-${i}`
- stop.products.forEach((row: any, j: number) => {
- row.id ||= `dp-new-${i}-${j}`
- row.planProductId = resolve(row)
- })
- })
- return clone(saved)
- }
- }
- }
- const api = new Function(
- ...Object.keys(b),
- ts.transpile(code, { target: ts.ScriptTarget.ESNext }) + `;return {${names.join(',')}}`
- )(...Object.values(b))
- return { b, api, writes, events, saved: () => saved }
- }
- for (const mobile of [false, true]) {
- const platform = mobile ? 'H5' : 'Web'
- test(`${platform} actual edit/save/reopen/save keeps all existing and freshly assigned child IDs`, async () => {
- const h = harness(mobile)
- await h.api.loadPlanForEdit('plan')
- h.b.loadForm.value.products.push({
- ...line,
- packageSpec: '袋',
- id: undefined,
- planProductId: undefined
- })
- h.b.deliveryForms.value.push({
- ...stops.createEmptyDeliveryForm(2),
- products: [{ ...line, packageSpec: '袋' }]
- })
- await h.api.handleSubmit('save')
- assert.equal(h.b.innerVisible.value, false)
- assert.deepEqual(h.events.at(-1), ['success', { planId: 'plan', arranged: false }])
- const saved = clone(h.saved())
- await h.api.loadPlanForEdit('plan')
- await h.api.handleSubmit('save')
- const payload = h.writes[1]
- assert.deepEqual(
- payload.products.map((p: any) => p.id),
- saved.products.map((p: any) => p.id)
- )
- assert.equal(payload.load.id, saved.load.id)
- assert.deepEqual(
- payload.load.products.map((p: any) => p.id),
- saved.load.products.map((p: any) => p.id)
- )
- assert.deepEqual(
- payload.deliveries.map((d: any) => [d.id, ...d.products.map((p: any) => p.id)]),
- saved.deliveries.map((d: any) => [d.id, ...d.products.map((p: any) => p.id)])
- )
- assert.ok(payload.load.products.every((p: any) => p.planProductId))
- assert.ok(payload.deliveries.every((d: any) => d.products.every((p: any) => p.planProductId)))
- })
- test(`${platform} actual copy handler strips source parent/product IDs from submit payload`, async () => {
- const h = harness(mobile)
- await h.api.loadPlanForCopy('plan')
- const payload = h.api.buildPlanCommonPayload()
- assert.equal(payload.load.id, undefined)
- assert.ok(payload.products.every((p: any) => !p.id))
- assert.ok(payload.load.products.every((p: any) => !p.id && !p.planProductId))
- assert.ok(
- payload.deliveries.every(
- (d: any) => !d.id && d.products.every((p: any) => !p.id && !p.planProductId)
- )
- )
- })
- }
|