feat:出库单修改功能

This commit is contained in:
zhouz
2026-07-24 10:35:50 +08:00
parent 8a9d488ac2
commit ac19f00697
14 changed files with 257 additions and 100 deletions

View File

@@ -70,10 +70,10 @@ public class IostorInvController {
}
@PutMapping("/update")
@Operation(summary = "更新出库单主表")
@Operation(summary = "更新出库单主表及明细")
@PreAuthorize("@ss.hasPermission('wms:iostor-inv:update')")
public CommonResult<Boolean> updateIostorInv(@Valid @RequestBody IostorInvSaveReqVO updateReqVO) {
iostorInvService.updateIostorInv(updateReqVO);
public CommonResult<Boolean> updateIostorInv(@Valid @RequestBody IostorInvUpdateReqVO reqVO) {
iostorInvService.updateOutbound(reqVO);
return success(true);
}
@@ -99,9 +99,20 @@ public class IostorInvController {
@Operation(summary = "获得出入库单主表")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')")
public CommonResult<IostorInvRespVO> getIostorInv(@RequestParam("id") String id) {
public CommonResult<IostorInvRespVO> getIostorInv(@RequestParam("id") Long id) {
IostorInvDO iostorInv = iostorInvService.getIostorInv(id);
return success(BeanUtils.toBean(iostorInv, IostorInvRespVO.class));
IostorInvRespVO respVO = BeanUtils.toBean(iostorInv, IostorInvRespVO.class);
respVO.setDetails(iostorInvService.getIostorInvDetails(id));
return success(respVO);
}
@GetMapping("/details")
@Operation(summary = "获得出入库单全部明细")
@Parameter(name = "iostorinvId", description = "出入库单主表标识", required = true)
@PreAuthorize("@ss.hasPermission('wms:iostor-inv:query')")
public CommonResult<List<IostorInvDetailRespVO>> getIostorInvDetails(
@RequestParam("iostorinvId") Long iostorinvId) {
return success(iostorInvService.getIostorInvDetails(iostorinvId));
}
@GetMapping("/page")

View File

@@ -19,6 +19,10 @@ public class IostorInvCreateReqVO {
@NotEmpty(message = "单据类型不能为空")
private String billType;
@Schema(description = "单据状态", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "单据状态不能为空")
private String billStatus;
@Schema(description = "仓库标识", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "仓库标识不能为空")
private String storId;

View File

@@ -0,0 +1,14 @@
package cn.code.nl.module.wms.controller.admin.iostorinv.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 出入库单编辑明细 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class IostorInvDetailRespVO extends IostorInvCreateReqVO.Detail {
@Schema(description = "物料名称")
private String materialName;
}

View File

@@ -130,4 +130,7 @@ public class IostorInvRespVO implements VO {
@ExcelProperty("回传时间")
private String uploadTime;
@Schema(description = "出入库单明细")
private List<IostorInvDetailRespVO> details;
}

View File

@@ -0,0 +1,16 @@
package cn.code.nl.module.wms.controller.admin.iostorinv.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Schema(description = "管理后台 - 出库单修改 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class IostorInvUpdateReqVO extends IostorInvCreateReqVO {
@Schema(description = "出入库单主表标识", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "出入库单主表标识不能为空")
private Long iostorinvId;
}

View File

@@ -12,6 +12,7 @@ import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryPageReqVO;
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.AvailableInventoryRespVO;
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.IostorInvDetailRespVO;
import cn.code.nl.module.wms.controller.admin.iostorinvdtl.vo.*;
/**
@@ -47,6 +48,9 @@ public interface IostorinvDtlMapper extends BaseMapperX<IostorinvDtlDO> {
List<AvailableInventoryRespVO> selectAvailableInventoryByVehicleCodesForUpdate(
@Param("storId") String storId, @Param("vehicleCodes") Collection<String> vehicleCodes);
/** 查询指定出入库单的编辑明细,并带出物料名称。 */
List<IostorInvDetailRespVO> selectEditDetails(@Param("iostorinvId") Long iostorinvId);
default PageResult<IostorinvDtlDO> selectPage(IostorinvDtlPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<IostorinvDtlDO>()
.eqIfPresent(IostorinvDtlDO::getIostorinvId, reqVO.getIostorinvId())

View File

@@ -4,6 +4,7 @@ import java.util.*;
import jakarta.validation.*;
import cn.code.nl.module.wms.controller.admin.iostorinv.vo.*;
import cn.code.nl.module.wms.dal.dataobject.iostorinv.IostorInvDO;
import cn.code.nl.module.wms.dal.dataobject.iostorinvdtl.IostorinvDtlDO;
import cn.code.nl.framework.common.pojo.PageResult;
import cn.code.nl.framework.common.pojo.PageParam;
@@ -53,6 +54,11 @@ public interface IostorInvService {
*/
void updateIostorInv(@Valid IostorInvSaveReqVO updateReqVO);
/**
* 更新出库单主表并替换全部明细。
*/
void updateOutbound(@Valid IostorInvUpdateReqVO reqVO);
/**
* 删除出入库单主表
*
@@ -73,7 +79,12 @@ public interface IostorInvService {
* @param id 编号
* @return 出入库单主表
*/
IostorInvDO getIostorInv(String id);
IostorInvDO getIostorInv(Long id);
/**
* 获得出入库单的全部明细。
*/
List<IostorInvDetailRespVO> getIostorInvDetails(Long id);
/**
* 获得出入库单主表分页

View File

@@ -90,16 +90,24 @@ public class IostorInvServiceImpl implements IostorInvService {
iostorInv.setBillType(reqVO.getBillType());
iostorInv.setBizDate(reqVO.getBizDate());
iostorInv.setStorId(reqVO.getStorId());
iostorInv.setBillStatus("10");
iostorInv.setBillStatus(reqVO.getBillStatus());
iostorInv.setRemark(reqVO.getRemark());
iostorInv.setDetailCount(reqVO.getDetails().size());
iostorInv.setTotalWeight(totalWeight);
iostorInvMapper.insert(iostorInv);
for (int index = 0; index < reqVO.getDetails().size(); index++) {
IostorInvCreateReqVO.Detail detail = reqVO.getDetails().get(index);
insertOutboundDetails(iostorInv.getIostorinvId(), reqVO.getBillStatus(),
reqVO.getDetails(), inventorySnapshot);
return iostorInv.getIostorinvId();
}
private void insertOutboundDetails(Long iostorinvId, String billStatus,
List<IostorInvCreateReqVO.Detail> details,
Map<Long, AvailableInventoryRespVO> inventorySnapshot) {
for (int index = 0; index < details.size(); index++) {
IostorInvCreateReqVO.Detail detail = details.get(index);
IostorinvDtlDO detailDO = new IostorinvDtlDO();
detailDO.setIostorinvId(iostorInv.getIostorinvId());
detailDO.setIostorinvId(iostorinvId);
detailDO.setSeqNo(index + 1);
AvailableInventoryRespVO inventory = inventorySnapshot.get(detail.getGroupId());
detailDO.setMaterialCode(inventory == null ? detail.getMaterialCode() : inventory.getMaterialCode());
@@ -108,7 +116,7 @@ public class IostorInvServiceImpl implements IostorInvService {
detailDO.setPlanQty(detail.getPlanQty());
detailDO.setUnassignQty(detail.getPlanQty());
detailDO.setAssignQty(BigDecimal.ZERO);
detailDO.setBillStatus("10");
detailDO.setBillStatus(billStatus);
detailDO.setQtyUnitId(inventory == null ? detail.getQtyUnitId() : inventory.getQtyUnitId());
detailDO.setSourceBillCode(inventory == null ? detail.getSourceBillCode() : inventory.getExtCode());
detailDO.setSourceBillType(inventory == null ? detail.getSourceBillType() : inventory.getExtType());
@@ -116,7 +124,6 @@ public class IostorInvServiceImpl implements IostorInvService {
detailDO.setRemark(detail.getRemark());
iostorinvDtlMapper.insert(detailDO);
}
return iostorInv.getIostorinvId();
}
private Map<Long, AvailableInventoryRespVO> validateAndLockInventory(IostorInvCreateReqVO reqVO) {
@@ -199,6 +206,32 @@ public class IostorInvServiceImpl implements IostorInvService {
iostorInvMapper.updateById(updateObj);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateOutbound(IostorInvUpdateReqVO reqVO) {
validateIostorInvExists(String.valueOf(reqVO.getIostorinvId()));
Map<Long, AvailableInventoryRespVO> inventorySnapshot = validateAndLockInventory(reqVO);
BigDecimal totalWeight = reqVO.getDetails().stream()
.map(IostorInvCreateReqVO.Detail::getPlanQty)
.reduce(BigDecimal.ZERO, BigDecimal::add);
IostorInvDO updateObj = new IostorInvDO();
updateObj.setIostorinvId(reqVO.getIostorinvId());
updateObj.setBillType(reqVO.getBillType());
updateObj.setBillStatus(reqVO.getBillStatus());
updateObj.setBizDate(reqVO.getBizDate());
updateObj.setStorId(reqVO.getStorId());
updateObj.setRemark(reqVO.getRemark());
updateObj.setDetailCount(reqVO.getDetails().size());
updateObj.setTotalWeight(totalWeight);
iostorInvMapper.updateById(updateObj);
iostorinvDtlMapper.delete(new LambdaQueryWrapperX<IostorinvDtlDO>()
.eq(IostorinvDtlDO::getIostorinvId, reqVO.getIostorinvId()));
insertOutboundDetails(reqVO.getIostorinvId(), reqVO.getBillStatus(),
reqVO.getDetails(), inventorySnapshot);
}
@Override
public void deleteIostorInv(String id) {
// 校验存在
@@ -221,10 +254,15 @@ public class IostorInvServiceImpl implements IostorInvService {
}
@Override
public IostorInvDO getIostorInv(String id) {
public IostorInvDO getIostorInv(Long id) {
return iostorInvMapper.selectById(id);
}
@Override
public List<IostorInvDetailRespVO> getIostorInvDetails(Long id) {
return iostorinvDtlMapper.selectEditDetails(id);
}
@Override
public PageResult<IostorInvDO> getIostorInvPage(IostorInvPageReqVO pageReqVO) {
PageResult<IostorInvDO> pageResult = iostorInvMapper.selectPage(pageReqVO);

View File

@@ -92,4 +92,25 @@
FOR UPDATE
</select>
<select id="selectEditDetails"
resultType="cn.code.nl.module.wms.controller.admin.iostorinv.vo.IostorInvDetailRespVO">
SELECT d.material_code,
d.material_id,
mb.material_name,
d.pcsn,
d.plan_qty,
d.qty_unit_id,
d.source_bill_code,
d.source_bill_type,
d.source_billdtl_id,
d.remark
FROM wms_iostorinvdtl d
LEFT JOIN base_materialbase mb
ON mb.material_id = d.material_id
AND mb.deleted = 0
WHERE d.iostorinv_id = #{iostorinvId}
AND d.deleted = 0
ORDER BY d.seq_no, d.iostorinvdtl_id
</select>
</mapper>

View File

@@ -64,10 +64,9 @@ class IostorInvServiceLocalSpringTest {
@Test
void shouldCreateOutboundUsingLockedInventoryIdentityInsteadOfClientUnitAndSource() {
String id = iostorInvService.createOutbound(buildRequest());
Long id = iostorInvService.createOutbound(buildRequest());
assertNotNull(id);
assertFalse(id.isBlank());
jdbcTemplate.queryForObject("SELECT * FROM wms_iostorinv WHERE iostorinv_id = ?", (rs, rowNum) -> {
assertEquals("OUT-TEST-0001", rs.getString("bill_code"));
assertEquals("OUT", rs.getString("io_type"));
@@ -97,12 +96,12 @@ class IostorInvServiceLocalSpringTest {
assertFalse(details.get(0).detailId().isBlank());
assertFalse(details.get(1).detailId().isBlank());
assertNotEquals(details.get(0).detailId(), details.get(1).detailId());
assertEquals(id, details.get(0).headerId());
assertEquals(id, details.get(1).headerId());
assertEquals(new DetailRow(details.get(0).detailId(), id, 1, "MAT-01", "MID-01", "PCSN-01",
assertEquals(id.toString(), details.get(0).headerId());
assertEquals(id.toString(), details.get(1).headerId());
assertEquals(new DetailRow(details.get(0).detailId(), id.toString(), 1, "MAT-01", "MID-01", "PCSN-01",
new BigDecimal("12.500"), BigDecimal.ZERO.setScale(3), new BigDecimal("12.500"),
"DB-KG", "数据库千克", "DB-SRC-01", "DB-TYPE", "DB-DTL-01", "明细一"), details.get(0));
assertEquals(new DetailRow(details.get(1).detailId(), id, 2, "MAT-02", "MID-02", "PCSN-02",
assertEquals(new DetailRow(details.get(1).detailId(), id.toString(), 2, "MAT-02", "MID-02", "PCSN-02",
new BigDecimal("7.250"), BigDecimal.ZERO.setScale(3), new BigDecimal("7.250"),
"DB-KG", "数据库千克", "DB-SRC-02", "DB-TYPE", "DB-DTL-02", "明细二"), details.get(1));
}
@@ -218,6 +217,7 @@ class IostorInvServiceLocalSpringTest {
private IostorInvCreateReqVO buildRequest() {
IostorInvCreateReqVO request = new IostorInvCreateReqVO();
request.setBillType("销售出库");
request.setBillStatus("生成");
request.setStorId("STOR-01");
request.setBizDate(LocalDateTime.of(2026, 7, 22, 0, 0));
request.setRemark("主表备注");

View File

@@ -27,6 +27,7 @@ export namespace WmsIostorInvApi {
creator?: string; // 创建者标识
creatorName?: string; // 创建者名称
createTime?: Dayjs | string; // 创建时间
details?: OutboundDetail[]; // 出入库单明细
disOptid: string; // 分配人
disTime?: Dayjs | string; // 分配时间
confirmOptid: string; // 确认人
@@ -64,12 +65,18 @@ export namespace WmsIostorInvApi {
/** 出库单新增请求 */
export interface OutboundCreateReq {
billType: string; // 单据类型
billStatus: string; // 单据状态
storId: string; // 仓库标识
bizDate: number; // 业务日期(毫秒时间戳)
remark?: string; // 备注
details: OutboundDetail[]; // 出库单明细
}
/** 出库单修改请求 */
export interface OutboundUpdateReq extends OutboundCreateReq {
iostorinvId: string;
}
/** 可用库存 */
export interface AvailableInventory {
groupId: number | string; // 组盘记录标识
@@ -119,6 +126,13 @@ export function getIostorInv(id: string) {
);
}
/** 查询出入库单全部明细 */
export function getIostorInvDetails(iostorinvId: string) {
return requestClient.get<WmsIostorInvApi.OutboundDisplayDetail[]>(
`/wms/iostor-inv/details?iostorinvId=${encodeURIComponent(iostorinvId)}`,
);
}
/** 新增出入库单主表 */
export function createIostorInv(data: WmsIostorInvApi.IostorInv) {
return requestClient.post('/wms/iostor-inv/create', data);
@@ -129,6 +143,11 @@ export function updateIostorInv(data: WmsIostorInvApi.IostorInv) {
return requestClient.put('/wms/iostor-inv/update', data);
}
/** 修改出库单主表及明细 */
export function updateOutbound(data: WmsIostorInvApi.OutboundUpdateReq) {
return requestClient.put('/wms/iostor-inv/update', data);
}
/** 删除出入库单主表 */
export function deleteIostorInv(id: number) {
return requestClient.delete(`/wms/iostor-inv/delete?id=${id}`);

View File

@@ -9,37 +9,37 @@ import { Button, Input, InputNumber, message, Space, Table } from 'antdv-next';
import dayjs from 'dayjs';
import { useVbenForm } from '#/adapter/form';
import { getSimpleDictDataList } from '#/api/system/dict/data';
import { getBsrealStorAttrSimpleList } from '#/api/wms/bsrealstorattr';
import {
createOutbound,
getIostorInv,
updateIostorInv,
getIostorInvDetails,
updateOutbound,
} from '#/api/wms/iostorinv';
import { $t } from '#/locales';
import { useFormSchema } from '../data';
import { summarizeDetails } from './detail-summary';
import InventorySelectComponent from './inventory-select.vue';
import ManualDetailComponent from './manual-detail.vue';
import {
buildOutboundPayload,
filterOutboundBillTypeOptions,
mergeOutboundInventory,
type OutboundFormDetail,
shouldApplyEditResult,
shouldClearDetailsForWarehouseChange,
} from './outbound-form';
import { DICT_TYPE } from '@vben/constants';
import { getDictOptions } from '@vben/hooks';
const emit = defineEmits(['success']);
const formData = ref<WmsIostorInvApi.IostorInv>();
const details = ref<OutboundFormDetail[]>([]);
const currentStorId = ref<string>();
let manualRowSequence = 0;
let billTypeRequest: null | ReturnType<typeof getSimpleDictDataList> = null;
let mainModalOpen = false;
let mainOpenToken = 0;
let activeEditId: string | undefined;
let suppressWarehouseChange = false;
const isEdit = computed(() => Boolean(formData.value?.iostorinvId));
const getTitle = computed(() =>
@@ -48,17 +48,6 @@ const getTitle = computed(() =>
: '出库单新增',
);
const [LegacyForm, legacyFormApi] = useVbenForm({
commonConfig: {
componentProps: { class: 'w-full' },
formItemClass: 'col-span-2',
labelWidth: 80,
},
layout: 'horizontal',
schema: useFormSchema(),
showDefaultActions: false,
});
async function handleWarehouseChange(nextStorId?: string) {
const shouldClear = shouldClearDetailsForWarehouseChange(
currentStorId.value,
@@ -78,7 +67,7 @@ const [OutboundForm, outboundFormApi] = useVbenForm({
labelWidth: 88,
},
handleValuesChange: (values) => {
if (Object.hasOwn(values, 'storId')) {
if (!suppressWarehouseChange && Object.hasOwn(values, 'storId')) {
void handleWarehouseChange(values.storId);
}
},
@@ -108,7 +97,7 @@ const [OutboundForm, outboundFormApi] = useVbenForm({
component: 'Select',
componentProps: {
allowClear: true,
options: [],
options: getDictOptions(DICT_TYPE.WMS_OUT_BILL_TYPE),
placeholder: '请选择业务类型',
},
fieldName: 'billType',
@@ -116,11 +105,15 @@ const [OutboundForm, outboundFormApi] = useVbenForm({
rules: 'required',
},
{
component: 'Input',
componentProps: { disabled: true },
defaultValue: '生成',
component: 'Select',
componentProps: {
allowClear: true,
options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS),
placeholder: '请选择单据状态',
},
fieldName: 'billStatus',
label: '单据状态',
rules: 'required',
},
{
component: 'InputNumber',
@@ -164,28 +157,6 @@ const [ManualDetail, manualDetailApi] = useVbenModal({
destroyOnClose: true,
});
async function loadBillTypeOptions() {
billTypeRequest ??= getSimpleDictDataList();
const request = billTypeRequest;
try {
const dictItems = await request;
outboundFormApi.updateSchema([
{
componentProps: {
allowClear: true,
options: filterOutboundBillTypeOptions(dictItems),
placeholder: '请选择业务类型',
},
fieldName: 'billType',
},
]);
} catch {
message.error('出库业务类型加载失败,请稍后重试');
} finally {
if (billTypeRequest === request) billTypeRequest = null;
}
}
const columns = [
{ key: 'index', title: '序号', width: 60 },
{ dataIndex: 'materialCode', key: 'materialCode', title: '物料编码', width: 130 },
@@ -265,34 +236,23 @@ function validateDetails() {
const [Modal, modalApi] = useVbenModal({
async onConfirm() {
if (isEdit.value) {
const { valid } = await legacyFormApi.validate();
if (!valid) return;
modalApi.lock();
try {
await updateIostorInv(
(await legacyFormApi.getValues()) as WmsIostorInvApi.IostorInv,
);
await modalApi.close();
emit('success');
message.success($t('ui.actionMessage.operationSuccess'));
} finally {
modalApi.unlock();
}
return;
}
const { valid } = await outboundFormApi.validate();
if (!valid || !validateDetails()) return;
const values = await outboundFormApi.getValues();
modalApi.lock();
try {
await createOutbound(
buildOutboundPayload(
const payload = buildOutboundPayload(
{ ...values, bizDate: dayjs(values.bizDate).valueOf() },
details.value,
),
);
if (isEdit.value) {
await updateOutbound({
...payload,
iostorinvId: formData.value!.iostorinvId,
});
} else {
await createOutbound(payload);
}
await modalApi.close();
emit('success');
message.success($t('ui.actionMessage.operationSuccess'));
@@ -318,17 +278,32 @@ const [Modal, modalApi] = useVbenModal({
formData.value = undefined;
details.value = [];
currentStorId.value = undefined;
suppressWarehouseChange = true;
try {
await outboundFormApi.resetForm();
await outboundFormApi.updateSchema([
{
componentProps: {
allowClear: true,
disabled: false,
options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS),
placeholder: '请选择单据状态',
},
fieldName: 'billStatus',
},
]);
if (!mainModalOpen || mainOpenToken !== token || activeEditId) return;
await outboundFormApi.setValues({
billCode: '保存时自动生成',
billStatus: '生成',
billStatus: '10',
bizDate: dayjs(),
detailCount: 0,
totalWeight: '0.000',
});
} finally {
suppressWarehouseChange = false;
}
if (!mainModalOpen || mainOpenToken !== token || activeEditId) return;
await loadBillTypeOptions();
return;
}
const editId = data.iostorinvId;
@@ -336,7 +311,10 @@ const [Modal, modalApi] = useVbenModal({
formData.value = data;
modalApi.lock();
try {
const editResult = await getIostorInv(editId);
const [editResult, editDetails] = await Promise.all([
getIostorInv(editId),
getIostorInvDetails(editId),
]);
if (
!shouldApplyEditResult(
mainModalOpen,
@@ -349,7 +327,38 @@ const [Modal, modalApi] = useVbenModal({
return;
}
formData.value = editResult;
await legacyFormApi.setValues(editResult);
suppressWarehouseChange = true;
try {
await outboundFormApi.resetForm();
await outboundFormApi.updateSchema([
{
componentProps: {
allowClear: true,
disabled: true,
options: getDictOptions(DICT_TYPE.WMS_IO_BILL_STATUS),
placeholder: '请选择单据状态',
},
fieldName: 'billStatus',
},
]);
details.value = editDetails.map((detail, index) => ({
...detail,
rowKey: `edit-${editId}-${index}`,
}));
await outboundFormApi.setValues({
billCode: editResult.billCode,
billStatus: editResult.billStatus,
billType: editResult.billType,
bizDate: editResult.bizDate ? dayjs(editResult.bizDate) : undefined,
detailCount: details.value.length,
remark: editResult.remark,
storId: editResult.storId,
totalWeight: Number(editResult.totalWeight || 0).toFixed(3),
});
currentStorId.value = editResult.storId;
} finally {
suppressWarehouseChange = false;
}
} finally {
if (
shouldApplyEditResult(
@@ -369,8 +378,7 @@ const [Modal, modalApi] = useVbenModal({
<template>
<Modal class="w-[1400px] max-w-[96vw]" :title="getTitle">
<LegacyForm v-if="isEdit" class="mx-4" />
<div v-else class="px-4">
<div class="px-4">
<OutboundForm />
<div class="mb-3 mt-1 flex items-center justify-between">
<span class="text-base font-medium">出库明细</span>

View File

@@ -34,7 +34,13 @@ describe('buildOutboundPayload', () => {
it('将业务日期转换成毫秒,并剥离所有仅展示字段和汇总字段', () => {
const bizDate = new Date('2026-07-22T08:30:00+08:00');
const payload = buildOutboundPayload(
{ billType: 'SALE', bizDate, remark: '主备注', storId: 'S-1' },
{
billStatus: '10',
billType: 'SALE',
bizDate,
remark: '主备注',
storId: 'S-1',
},
[
{
groupId: 11,
@@ -79,7 +85,7 @@ describe('buildOutboundPayload', () => {
it('手工汇总行不附带库存引用字段', () => {
const payload = buildOutboundPayload(
{ billType: 'SALE', bizDate: 1, storId: 'S-1' },
{ billStatus: '10', billType: 'SALE', bizDate: 1, storId: 'S-1' },
[{ materialCode: 'M-1', planQty: 2 }],
);

View File

@@ -24,6 +24,7 @@ export function shouldApplyEditResult(
export interface OutboundFormValues {
billType?: string;
billStatus?: string;
bizDate?: number | string | { valueOf: () => number };
remark?: string;
storId?: string;
@@ -48,6 +49,7 @@ export function buildOutboundPayload(
): WmsIostorInvApi.OutboundCreateReq {
return {
billType: values.billType!,
billStatus: values.billStatus!,
bizDate: Number(values.bizDate?.valueOf()),
details: details.map((detail) => ({
groupId: detail.groupId,