rsf-admin/src/i18n/en.js
@@ -51,6 +51,7 @@ before: 'Time Before' }, action: { search: 'Search', reset: 'Reset', expand: 'Expand', expandAll: 'Expand All', @@ -919,6 +920,7 @@ batch: 'batch', confirm: 'confirm', cancel: "cancel", query: "Query", bulkExport: "Bulk Export", continue: 'Continue Receipt', confirmSelect: 'Confirm Select', rsf-admin/src/i18n/zh.js
@@ -51,6 +51,7 @@ before: '结束时间' }, action: { search: '搜索', reset: '重置', expand: '展开', expandAll: '全部展开', @@ -970,6 +971,7 @@ selectSite: '选择站点', confirmSelect: '确认选择', cancel: "取消", query: "查询", top: "置顶", resort: "排序", subzone: '绑定分区', rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
@@ -36,13 +36,16 @@ Form, SaveButton, useRefresh, useGetList, } from 'react-admin'; import DialogCloseButton from "../../components/DialogCloseButton"; import { styled } from '@mui/material/styles'; import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting'; import { Grid, Stack } from "@mui/system"; import { Grid, Stack, width } from "@mui/system"; import request from '@/utils/request'; import SaveIcon from '@mui/icons-material/Save'; import debounce from "lodash/debounce"; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({ '& .css-1vooibu-MuiSvgIcon-root': { @@ -95,6 +98,62 @@ setOpen(false); } }; const CustomFilter = () => { const { filterValues, setFilters, refetch } = useListContext('deliveryItem'); const [formValues, setFormValues] = useState(filterValues); const handleChange = (event) => { setFormValues(formValues => ({ ...formValues, [event.target.name]: event.target.value })); }; const handleSubmit = (event) => { setParams(formValues) }; return ( <Form> <Grid container rowSpacing={2} columnSpacing={2} > <Stack> <TextInput source="condition" label="common.action.search" resettable defaultValue={params?.condition} onChange={handleChange} /> </Stack> <Stack> <TextInput source="matnrName" label="table.field.deliveryItem.matnrName" defaultValue={params?.matnrName} onChange={handleChange} /> </Stack> <Stack> <TextInput source="matnrCode" label="table.field.deliveryItem.matnrCode" defaultValue={params?.matnrCode} onChange={handleChange} /> </Stack> <Stack> <TextInput source="splrName" label="table.field.deliveryItem.splrName" defaultValue={params?.splrName} onChange={handleChange} /> </Stack> </Grid> <DialogActions> <Toolbar sx={{ width: '100%', justifyContent: 'end' }} > <SaveButton onClick={handleSubmit} label={"toolbar.query"} /> </Toolbar> </DialogActions> </Form> ); }; return ( <Dialog open={open} @@ -129,9 +188,8 @@ }), marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0, }} storeKey='selectDelivery' queryOptions={params} filters={<CustomFilter />} queryOptions={{ meta: { ...params } }} empty={false} sort={{ field: "create_time", order: "desc" }} actions={( @@ -143,7 +201,7 @@ > <StyledDatagrid preferenceKey='deliveryItem' bulkActionButtons={() => <></>} bulkActionButtons={<AddOutStockButton setOpen={setOpen}/>} rowClick={(id, resource, record) => false} expand={false} expandSingle={true} @@ -173,63 +231,25 @@ export default OutOrderModal; const CustomFilter = () => { const { filterValues, setFilters } = useListContext('deliveryItem'); const [formValues, setFormValues] = useState(filterValues); const handleChange = (event) => { setFormValues(formValues => ({ ...formValues, [event.target.name]: event.target.value })); }; const handleSubmit = (event) => { console.log('---------->'); console.log(formValues); event.preventDefault(); setFilters(formValues, null, true); }; const AddOutStockButton = (props) => { const { setOpen } = props; const { selectedIds, onUnselectItems } = useListContext(); const notify = useNotify(); const confirm = async (event) => { console.log(selectedIds); const res = await request.post(`/outStock/generate/orders`, {ids: selectedIds}); if (res?.data?.code === 200) { notify(res.data.msg); } else { notify(res.data.msg); } onUnselectItems(); setOpen(false); } return ( <Form> <Grid container rowSpacing={2} columnSpacing={2} > <Stack> <TextInput source="matnrName" label="table.field.deliveryItem.matnrName" resettable onChange={handleChange} /> </Stack> <Stack> <TextInput source="matnrCode" label="table.field.deliveryItem.matnrCode" resettable onChange={handleChange} /> </Stack> <Stack> <TextInput source="splrName" label="table.field.deliveryItem.splrName" resettable onChange={handleChange} /> </Stack> <Stack> <TextInput source="splrName" label="table.field.deliveryItem.splrName" resettable onChange={handleChange} /> </Stack> </Grid> <DialogActions> <Toolbar sx={{ width: '100%', justifyContent: 'end' }} > <SaveButton onClick={handleSubmit}/> {/* <Button variant="contained" label="toolbar.confirm" startIcon={<SaveIcon />} onClick={handleSubmit} /> */} </Toolbar> </DialogActions> </Form> ); }; <Button label={"toolbar.confirmSelect"} onClick={confirm}> <CheckCircleIcon /> </Button> ) } rsf-server/src/main/java/com/vincent/rsf/server/common/domain/PageParam.java
@@ -71,7 +71,7 @@ } public QueryWrapper<T> buildWrapper(boolean like, List<String> fields) { return this.buildWrapper(like, null,"create_time", fields); return this.buildWrapper(like, null, "create_time", fields); } @SuppressWarnings("all") @@ -133,26 +133,26 @@ if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) { List<String> columns = new ArrayList<>(); for (Field field : Cools.getAllFields(cls)){ for (Field field : Cools.getAllFields(cls)) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())){ || Modifier.isTransient(field.getModifiers())) { continue; } if (field.isAnnotationPresent(TableField.class)){ if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } } String column = Utils.toSymbolCase(field.getName(), '_'); String column = Utils.toSymbolCase(field.getName(), '_'); columns.add(column); } if (!columns.isEmpty()) { queryWrapper.and(wrapper -> { for (int i=0;i<columns.size();i++){ for (int i = 0; i < columns.size(); i++) { String column = columns.get(i); String condition = where.getCondition(); if (i == 0) { @@ -168,7 +168,7 @@ } @SuppressWarnings("all") public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer,String timeField, List<String> fields) { public QueryWrapper<T> buildWrapper(boolean like, Consumer<QueryWrapper<T>> consumer, String timeField, List<String> fields) { QueryWrapper<T> queryWrapper = new QueryWrapper<>(); Map<String, Object> map = where.getMap(); for (String key : map.keySet()) { @@ -192,9 +192,9 @@ key = Utils.toSymbolCase(key, '_'); } if (like && !fields.contains(key)) { queryWrapper.like("`" + key + "`", val); queryWrapper.like("`" + key + "`", val); } else { queryWrapper.eq("`" + key + "`", val); queryWrapper.eq("`" + key + "`", val); } } } @@ -223,21 +223,21 @@ if (!Cools.isEmpty(where.getCondition()) && !Cools.isEmpty(cls)) { List<String> columns = new ArrayList<>(); for (Field field : Cools.getAllFields(cls)){ for (Field field : Cools.getAllFields(cls)) { if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())){ || Modifier.isTransient(field.getModifiers())) { continue; } if (field.isAnnotationPresent(TableField.class)){ if (field.isAnnotationPresent(TableField.class)) { TableField annotation = field.getAnnotation(TableField.class); if (!annotation.exist()) { continue; } } String column = Utils.toSymbolCase(field.getName(), '_'); String column = Utils.toSymbolCase(field.getName(), '_'); columns.add(column); } // if (!columns.isEmpty()) { @@ -254,7 +254,7 @@ // } if (!columns.isEmpty()) { queryWrapper.and(wrapper -> { for (int i=0;i<columns.size();i++){ for (int i = 0; i < columns.size(); i++) { String column = columns.get(i); String condition = where.getCondition(); if (i == 0) { rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/OutStockController.java
@@ -190,4 +190,18 @@ } ExcelUtil.build(ExcelUtil.create(orderTemplates, AsnOrderTemplate.class), response); } @PreAuthorize("hasAuthority('manager:outStock:update')") @ApiOperation("通过DO单生成出库单") @PostMapping("/outStock/generate/orders") public R genOutStock(@RequestBody Map<String, Object> params) { if (Objects.isNull(params.get("ids"))) { return R.error("参数不能为空!!"); } List<Long> ids = (List<Long>) params.get("ids"); return outStockService.genOutStock(ids); } } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/OutStockService.java
@@ -12,4 +12,6 @@ public interface OutStockService extends IService<AsnOrder> { R cancelOutOrder(String id); R genOutStock(List<Long> ids); } rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -11,10 +11,7 @@ import com.vincent.rsf.server.api.service.ReportMsgService; import com.vincent.rsf.server.manager.controller.params.AsnOrderAndItemsParams; import com.vincent.rsf.server.manager.controller.params.BatchUpdateParam; import com.vincent.rsf.server.manager.entity.AsnOrder; import com.vincent.rsf.server.manager.entity.AsnOrderItem; import com.vincent.rsf.server.manager.entity.AsnOrderItemLog; import com.vincent.rsf.server.manager.entity.AsnOrderLog; import com.vincent.rsf.server.manager.entity.*; import com.vincent.rsf.server.manager.enums.AsnExceStatus; import com.vincent.rsf.server.manager.mapper.AsnOrderMapper; import com.vincent.rsf.server.manager.mapper.PurchaseMapper; @@ -22,6 +19,7 @@ import com.vincent.rsf.server.system.constant.SerialRuleCode; import com.vincent.rsf.server.system.mapper.SerialRuleMapper; import com.vincent.rsf.server.system.utils.SerialRuleUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -42,29 +40,31 @@ public class OutStockServiceImpl extends ServiceImpl<AsnOrderMapper, AsnOrder> implements OutStockService { @Autowired private ReceiveMsgService receiveMsgService; @Autowired private ReportMsgService reportMsgService; @Resource private PurchaseMapper purchaseMapper; @Autowired private AsnOrderItemService asnOrderItemService; @Autowired private AsnOrderLogService asnOrderLogService; @Autowired private AsnOrderItemLogService asnOrderItemLogService; @Resource private SerialRuleMapper serialRuleMapper; @Autowired private DeliveryItemService deliveryItemService; @Autowired private DeliveryService deliveryService; @Autowired private MatnrService matnrService; /** * @author Ryan * @description 更新或保存明细 * @param * @return * @author Ryan * @description 更新或保存明细 * @time 2025/4/7 13:28 */ @Transactional(rollbackFor = Exception.class) private void svaeOrUpdateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) throws Exception{ private void svaeOrUpdateOrderItem(AsnOrderAndItemsParams params, Long loginUserId) throws Exception { AsnOrder orders = params.getOrders(); params.getItems().forEach(item -> { @@ -88,14 +88,14 @@ /** * @author Ryan * @description 删除原主单及明细,加入历史档 * @param * @return * @author Ryan * @description 删除原主单及明细,加入历史档 * @time 2025/3/19 19:53 */ @Transactional(rollbackFor = Exception.class) private void operateOrderLogs(AsnOrder asrder) throws Exception{ private void operateOrderLogs(AsnOrder asrder) throws Exception { if (Objects.isNull(asrder) || Objects.isNull(asrder.getId())) { throw new CoolException("参数不能为空!!"); } @@ -148,10 +148,10 @@ } /** * @author Ryan * @description 取消出库单据 * @param * @return * @author Ryan * @description 取消出库单据 * @time 2025/4/22 10:40 */ @Override @@ -174,4 +174,68 @@ } return R.ok("操作成功"); } /** * @param * @return * @author Ryan * @description 通过DO单生成出库单 * @time 2025/4/23 16:24 */ @Override @Transactional(rollbackFor = Exception.class) public R genOutStock(List<Long> ids) { if (Objects.isNull(ids) || ids.isEmpty()) { throw new CoolException("参数不能为空!!"); } List<DeliveryItem> items = deliveryItemService.list(new LambdaQueryWrapper<DeliveryItem>().in(DeliveryItem::getId, ids)); if (items.isEmpty()) { throw new CoolException("单据不存在!!"); } Map<Long, List<DeliveryItem>> listMap = items.stream().collect(Collectors.groupingBy(DeliveryItem::getDeliveryId)); listMap.keySet().forEach(key -> { //TODO 判断单据是否已经存在,如存在则累加修改子表,不存在才新建 Delivery delivery = deliveryService.getById(key); if (Objects.isNull(delivery)) { throw new CoolException("单据不存在!!"); } AsnOrder order = new AsnOrder(); BeanUtils.copyProperties(delivery, order); String ruleCode = SerialRuleUtils.generateRuleCode(SerialRuleCode.SYS_OUT_STOCK_CODE, order); if (Objects.isNull(ruleCode) || StringUtils.isBlank(ruleCode)) { throw new CoolException("编码规则错误:请检查 「SYS_OUT_STOCK_CODE」编码是否设置成功"); } order.setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_UN_EXCE.val) .setCode(ruleCode) .setPoId(delivery.getId()) .setId(null) .setPoCode(delivery.getCode()); if (!this.save(order)) { throw new CoolException("主单保存失败!!"); } List<AsnOrderItem> orderItems = new ArrayList<>(); listMap.get(key).forEach(item -> { AsnOrderItem orderItem = new AsnOrderItem(); BeanUtils.copyProperties(item, orderItem); orderItem.setId(null) .setPoCode(order.getPoCode()) .setAsnId(order.getId()) .setAsnCode(order.getCode()) .setPlatItemId(item.getPlatItemId()) .setPoDetlId(item.getId()); orderItems.add(orderItem); }); double sum = orderItems.stream().mapToDouble(AsnOrderItem::getAnfme).sum(); //修改计划数量 order.setAnfme(sum); if (!this.saveOrUpdate(order)) { throw new CoolException("主单数量修改失败!!"); } if (!asnOrderItemService.saveBatch(orderItems)) { throw new CoolException("明细保存失败!!"); } }); return R.ok(); } } rsf-server/src/main/java/com/vincent/rsf/server/system/controller/BaseController.java
@@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; /** * Created by vincent on 1/30/2024 @@ -42,6 +43,13 @@ } public <T extends BaseParam> T buildParam(Map<String, Object> map, Class<T> clz) { if (!Objects.isNull(map.get("meta"))) { Map<String, Object> meta = (Map<String, Object>) map.get("meta"); meta.keySet().forEach(key -> { map.put(key, meta.get(key)); }); map.remove("meta"); } T t = null; try { t = clz.getDeclaredConstructor().newInstance();