Release/test #2

Merged
admin merged 19 commits from release/test into main 2026-09-18 18:03:45 +08:00
4 changed files with 75 additions and 13 deletions
Showing only changes of commit bb94f88bb3 - Show all commits
@@ -162,10 +162,11 @@ test('requires public destination ids while keeping private addresses detached f
test('requires customs inspection when any cargo is a wooden product', () => {
const draft = validDraft()
draft.items[0].woodenProduct = true
draft.items.push({ ...draft.items[0], id: 'cargo-2' })
draft.customsInspection = null
assert.ok(validateFirstLegOrderDraft(draft).includes('第 1 条货物为木制品,“是否商检”必须选择“是”'))
assert.ok(validateFirstLegOrderDraft(draft).includes('第 1、2 条货物为木制品,“是否商检”必须选择“是”'))
draft.customsInspection = false
assert.ok(validateFirstLegOrderDraft(draft).includes('第 1 条货物为木制品,“是否商检”必须选择“是”'))
assert.ok(validateFirstLegOrderDraft(draft).includes('第 1、2 条货物为木制品,“是否商检”必须选择“是”'))
draft.customsInspection = true
assert.ok(!validateFirstLegOrderDraft(draft).some((message) => message.includes('为木制品')))
})
+7 -1
View File
@@ -141,9 +141,15 @@ export function validateFirstLegOrderDraft(draft: FirstLegOrderDraft) {
}
if (item.grossWeightKg <= 0) errors.push(`${line}毛重必须大于 0`)
if (item.volumeCbm <= 0) errors.push(`${line}体积必须大于 0`)
if (item.woodenProduct && draft.customsInspection !== true) errors.push(`${line}为木制品,“是否商检”必须选择“是”`)
})
const woodenCargoLines = draft.items
.map((item, index) => item.woodenProduct ? index + 1 : null)
.filter((index): index is number => index != null)
if (woodenCargoLines.length && draft.customsInspection !== true) {
errors.push(`第 ${woodenCargoLines.join('、')} 条货物为木制品,“是否商检”必须选择“是”`)
}
if (draft.fulfillmentType === 'ONE_CLICK_DROPSHIP') {
const groups = new Map<string, FirstLegCargoItem>()
draft.items.forEach((item) => {
@@ -299,6 +299,13 @@ test('selects platform destinations and uses customer-scoped server address book
assert.match(source, /createMerchantOrderAddress\(payload\)/)
assert.match(source, /updateMerchantOrderAddress\(form\.(?:senderAddressId|privateDestinationAddressId), payload\)/)
assert.match(source, /disableMerchantOrderAddress\(id\)/)
assert.match(source, /function findAddressBookEntryId\(addressType: CustomerOrderAddress\['addressType'\], snapshot: FirstLegPartySnapshot \| null\)/)
assert.match(source, /senderAddressId: findAddressBookEntryId\('PICKUP', order\.shipperPartySnapshot\)/)
assert.match(source, /privateDestinationAddressId: findAddressBookEntryId\('PRIVATE_DESTINATION', order\.consigneePartySnapshot\)/)
assert.match(source, /function selectPickupAddress\(id: string \| null \| undefined\)[\s\S]*?form\.shipperPartySnapshot = createEmptyPartySnapshot\('SHIPPER'\)/)
assert.match(source, /function selectPrivateAddress\(id: string \| null \| undefined\)[\s\S]*?form\.consigneePartySnapshot = createEmptyPartySnapshot\('CONSIGNEE'\)/)
assert.match(source, /const existingAddressId = findAddressBookEntryId\('PICKUP', snapshot\)[\s\S]*?相同的企业提货地址已存在,已为您选中/)
assert.match(source, /const existingAddressId = findAddressBookEntryId\('PRIVATE_DESTINATION', snapshot\)[\s\S]*?相同的企业私人仓地址已存在,已为您选中/)
assert.match(source, /v-model="form\.senderAddressId"/)
assert.match(source, /v-model="form\.privateDestinationAddressId"/)
assert.doesNotMatch(source, /localStorage|cc:first-leg:private-addresses/)
@@ -334,7 +341,7 @@ test('collects the backend-required first-leg fields', () => {
}
assert.match(source, /form\.channelName = channel\?\.channelName/)
assert.match(source, /v-model="item\.woodenProduct"/)
assert.match(source, /第 \{\{ woodenCargoLines\.join\('、'\) \}\} 条货物已勾选木制品/)
assert.match(source, /第 \{\{ woodenCargoLines\.join\('、'\) \}\} 条货物为木制品,请将“是否商检”选择为“是”/)
assert.match(source, /第 \{\{ index \+ 1 \}\} 条须商检/)
})
@@ -756,6 +756,25 @@ function removeCargoProductImage(item: FirstLegCargoItem) {
item.productImageError = ''
}
function normalizedAddressValue(value: string | null | undefined) {
return value?.trim().toLocaleLowerCase() ?? ''
}
function findAddressBookEntryId(addressType: CustomerOrderAddress['addressType'], snapshot: FirstLegPartySnapshot | null) {
if (!snapshot) return ''
const address = orderAddresses.value.find((item) => item.addressType === addressType
&& normalizedAddressValue(item.companyName || item.addressName) === normalizedAddressValue(snapshot.name)
&& normalizedAddressValue(item.contactName) === normalizedAddressValue(snapshot.contactName)
&& normalizedAddressValue(item.phone) === normalizedAddressValue(snapshot.phone)
&& normalizedAddressValue(item.email) === normalizedAddressValue(snapshot.email)
&& normalizedAddressValue(item.countryCode) === normalizedAddressValue(snapshot.countryRegion)
&& normalizedAddressValue(item.province) === normalizedAddressValue(snapshot.province)
&& normalizedAddressValue(item.city) === normalizedAddressValue(snapshot.city)
&& normalizedAddressValue(item.postalCode) === normalizedAddressValue(snapshot.postalCode)
&& normalizedAddressValue(item.addressLine) === normalizedAddressValue(snapshot.address))
return address == null ? '' : String(address.id)
}
function draftFromOrder(order: FirstLegOrder): FirstLegOrderDraft {
return {
inboundCode: order.businessSummary.inboundCode,
@@ -769,11 +788,11 @@ function draftFromOrder(order: FirstLegOrder): FirstLegOrderDraft {
receivingWarehouseId: order.receivingWarehouseId,
expectedDepartureDate: order.expectedDepartureDate,
shipperPartyId: order.shipperPartyId,
senderAddressId: '',
senderAddressId: findAddressBookEntryId('PICKUP', order.shipperPartySnapshot),
shipperPartySnapshot: order.shipperPartySnapshot ? { ...order.shipperPartySnapshot } : null,
shipper: order.shipper,
consigneePartyId: order.consigneePartyId,
privateDestinationAddressId: '',
privateDestinationAddressId: findAddressBookEntryId('PRIVATE_DESTINATION', order.consigneePartySnapshot),
consigneePartySnapshot: order.consigneePartySnapshot ? { ...order.consigneePartySnapshot } : null,
consignee: order.consignee,
priority: order.priority,
@@ -1000,9 +1019,19 @@ function syncPrivateDestinationName(value: string) {
if (form.consigneePartySnapshot) form.consigneePartySnapshot.name = value
}
function selectPrivateAddress(id: string) {
function selectPrivateAddress(id: string | null | undefined) {
const address = privateAddresses.value.find((item) => String(item.id) === id)
if (!address) return
if (!address) {
form.privateDestinationAddressId = ''
form.consigneePartyId = ''
form.consigneePartySnapshot = createEmptyPartySnapshot('CONSIGNEE')
form.consignee = ''
form.destination = ''
form.destinationCountryCode = ''
form.destinationWarehouseId = ''
form.destinationWarehouseName = ''
return
}
form.privateDestinationAddressId = String(address.id)
form.consigneePartyId = ''
form.consigneePartySnapshot = addressSnapshot(address, 'CONSIGNEE')
@@ -1039,9 +1068,16 @@ async function loadOrderAddresses() {
}
}
function selectPickupAddress(id: string) {
function selectPickupAddress(id: string | null | undefined) {
const address = pickupAddresses.value.find((item) => String(item.id) === id)
if (!address) return
if (!address) {
form.senderAddressId = ''
form.shipperPartyId = ''
form.shipperPartySnapshot = createEmptyPartySnapshot('SHIPPER')
form.shipper = ''
form.origin = ''
return
}
form.senderAddressId = String(address.id)
form.shipperPartyId = ''
form.shipperPartySnapshot = addressSnapshot(address, 'SHIPPER')
@@ -1079,6 +1115,12 @@ async function savePickupAddress() {
ElMessage.warning('请先完整填写提货地址和联系人资料')
return
}
const existingAddressId = findAddressBookEntryId('PICKUP', snapshot)
if (existingAddressId && existingAddressId !== form.senderAddressId) {
selectPickupAddress(existingAddressId)
ElMessage.info('相同的企业提货地址已存在,已为您选中')
return
}
try {
const payload = addressPayload('PICKUP', snapshot!, addressName)
if (form.senderAddressId) await updateMerchantOrderAddress(form.senderAddressId, payload)
@@ -1100,6 +1142,12 @@ async function savePrivateAddress() {
return
}
snapshot!.name = addressName
const existingAddressId = findAddressBookEntryId('PRIVATE_DESTINATION', snapshot)
if (existingAddressId && existingAddressId !== form.privateDestinationAddressId) {
selectPrivateAddress(existingAddressId)
ElMessage.info('相同的企业私人仓地址已存在,已为您选中')
return
}
try {
const payload = addressPayload('PRIVATE_DESTINATION', snapshot!, addressName)
if (form.privateDestinationAddressId) await updateMerchantOrderAddress(form.privateDestinationAddressId, payload)
@@ -1117,8 +1165,8 @@ async function removeOrderAddress(type: CustomerOrderAddress['addressType']) {
if (!id) return
try {
await disableMerchantOrderAddress(id)
if (type === 'PICKUP') form.senderAddressId = ''
else form.privateDestinationAddressId = ''
if (type === 'PICKUP') selectPickupAddress(null)
else selectPrivateAddress(null)
await loadOrderAddresses()
ElMessage.success('地址已从企业地址簿停用')
} catch (error) {
@@ -2057,7 +2105,7 @@ async function searchOrders(model: QueryModel) {
</el-form-item>
<el-form-item label="买单 / 退税" prop="taxMode" required><el-radio-group v-model="form.taxMode"><el-radio value="BUY_DECLARATION">买单</el-radio><el-radio value="TAX_REFUND">退税</el-radio></el-radio-group></el-form-item>
<el-form-item label="是否整柜" prop="transportMode" required><el-radio-group v-model="form.transportMode"><el-radio value="FCL">整柜</el-radio><el-radio value="LCL">散货</el-radio></el-radio-group></el-form-item>
<el-form-item label="是否商检" prop="customsInspection"><el-select v-model="form.customsInspection" clearable placeholder="暂不选择"><el-option label="是" :value="true" /><el-option label="否" :value="false" /></el-select><small v-if="woodenCargoLines.length && form.customsInspection !== true" class="field-guidance field-guidance--error">第 {{ woodenCargoLines.join('、') }} 条货物已勾选木制品,提交前“是否商检”必须选择“是”。</small></el-form-item>
<el-form-item label="是否商检" prop="customsInspection"><el-select v-model="form.customsInspection" clearable placeholder="暂不选择"><el-option label="是" :value="true" /><el-option label="否" :value="false" /></el-select><small v-if="woodenCargoLines.length && form.customsInspection !== true" class="field-guidance field-guidance--error">第 {{ woodenCargoLines.join('、') }} 条货物为木制品,请将“是否商检”选择为“是”。</small></el-form-item>
<el-form-item label="期望出货日期"><el-date-picker v-model="form.expectedDepartureDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择期望出货日期" /></el-form-item>
<el-form-item label="订单备注"><el-input v-model="form.customerRemark" type="textarea" :rows="3" resize="vertical" maxlength="300" show-word-limit placeholder="选填,例如:入仓前请电话联系" /></el-form-item>
</div>