提交基础采购
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseOrderItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseOrderItemVo;
|
||||
import com.klp.erp.service.IErpPurchaseOrderItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/purchaseOrderItem")
|
||||
public class ErpPurchaseOrderItemController extends BaseController {
|
||||
|
||||
private final IErpPurchaseOrderItemService orderItemService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpPurchaseOrderItemVo> list(ErpPurchaseOrderItemBo bo, PageQuery pageQuery) {
|
||||
return orderItemService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "采购订单明细", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpPurchaseOrderItemBo bo, HttpServletResponse response) {
|
||||
List<ErpPurchaseOrderItemVo> list = orderItemService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "采购订单明细", ErpPurchaseOrderItemVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{itemId}")
|
||||
public R<ErpPurchaseOrderItemVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long itemId) {
|
||||
return R.ok(orderItemService.queryById(itemId));
|
||||
}
|
||||
|
||||
@Log(title = "采购订单明细", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpPurchaseOrderItemBo bo) {
|
||||
return toAjax(orderItemService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购订单明细", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpPurchaseOrderItemBo bo) {
|
||||
return toAjax(orderItemService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购订单明细", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{itemIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] itemIds) {
|
||||
return toAjax(orderItemService.deleteWithValidByIds(Arrays.asList(itemIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReceiptBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReceiptVo;
|
||||
import com.klp.erp.service.IErpPurchaseReceiptService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/purchaseReceipt")
|
||||
public class ErpPurchaseReceiptController extends BaseController {
|
||||
|
||||
private final IErpPurchaseReceiptService receiptService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpPurchaseReceiptVo> list(ErpPurchaseReceiptBo bo, PageQuery pageQuery) {
|
||||
return receiptService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "采购收货记录", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpPurchaseReceiptBo bo, HttpServletResponse response) {
|
||||
List<ErpPurchaseReceiptVo> list = receiptService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "采购收货记录", ErpPurchaseReceiptVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{receiptId}")
|
||||
public R<ErpPurchaseReceiptVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long receiptId) {
|
||||
return R.ok(receiptService.queryById(receiptId));
|
||||
}
|
||||
|
||||
@Log(title = "采购收货记录", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpPurchaseReceiptBo bo) {
|
||||
return toAjax(receiptService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购收货记录", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpPurchaseReceiptBo bo) {
|
||||
return toAjax(receiptService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购收货记录", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{receiptIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] receiptIds) {
|
||||
return toAjax(receiptService.deleteWithValidByIds(Arrays.asList(receiptIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.erp.mapper.ErpPurchaseReportMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/erp/purchaseReport")
|
||||
public class ErpPurchaseReportController extends BaseController {
|
||||
|
||||
private final ErpPurchaseReportMapper reportMapper;
|
||||
|
||||
@Log(title = "采购汇总报表", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/summary")
|
||||
public R<Map<String, Object>> summary(@RequestParam(required = false) String beginTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
BigDecimal totalAmount = reportMapper.sumTotalAmount(beginTime, endTime);
|
||||
List<Map<String, Object>> bySupplier = reportMapper.sumAmountBySupplier(beginTime, endTime);
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("totalAmount", totalAmount);
|
||||
result.put("bySupplier", bySupplier);
|
||||
return R.ok(result);
|
||||
}
|
||||
|
||||
@Log(title = "采购价格趋势", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/trend")
|
||||
public R<List<Map<String, Object>>> priceTrend(@RequestParam(required = false) String beginTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
return R.ok(reportMapper.selectPriceTrend(beginTime, endTime));
|
||||
}
|
||||
|
||||
@Log(title = "供应商绩效", businessType = BusinessType.OTHER)
|
||||
@GetMapping("/supplierQuality")
|
||||
public R<List<Map<String, Object>>> supplierQuality(@RequestParam(required = false) String beginTime,
|
||||
@RequestParam(required = false) String endTime) {
|
||||
return R.ok(reportMapper.selectSupplierQuality(beginTime, endTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.erp.domain.bo.PurchaseRequirementAnalyzeBo;
|
||||
import com.klp.erp.domain.vo.PurchaseRequirementVo;
|
||||
import com.klp.erp.service.IErpPurchaseRequirementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/purchaseRequirement")
|
||||
public class ErpPurchaseRequirementController extends BaseController {
|
||||
|
||||
private final IErpPurchaseRequirementService purchaseRequirementService;
|
||||
|
||||
@Log(title = "采购需求分析", businessType = BusinessType.OTHER)
|
||||
@PostMapping("/analyze")
|
||||
public R<List<PurchaseRequirementVo>> analyze(@Validated @RequestBody PurchaseRequirementAnalyzeBo bo) {
|
||||
return R.ok(purchaseRequirementService.analyze(bo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnVo;
|
||||
import com.klp.erp.service.IErpPurchaseReturnService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/purchaseReturn")
|
||||
public class ErpPurchaseReturnController extends BaseController {
|
||||
|
||||
private final IErpPurchaseReturnService returnService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpPurchaseReturnVo> list(ErpPurchaseReturnBo bo, PageQuery pageQuery) {
|
||||
return returnService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "采购退货", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpPurchaseReturnBo bo, HttpServletResponse response) {
|
||||
List<ErpPurchaseReturnVo> list = returnService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "采购退货", ErpPurchaseReturnVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{returnId}")
|
||||
public R<ErpPurchaseReturnVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long returnId) {
|
||||
return R.ok(returnService.queryById(returnId));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpPurchaseReturnBo bo) {
|
||||
return toAjax(returnService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpPurchaseReturnBo bo) {
|
||||
return toAjax(returnService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{returnIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] returnIds) {
|
||||
return toAjax(returnService.deleteWithValidByIds(Arrays.asList(returnIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnItemVo;
|
||||
import com.klp.erp.service.IErpPurchaseReturnItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/purchaseReturnItem")
|
||||
public class ErpPurchaseReturnItemController extends BaseController {
|
||||
|
||||
private final IErpPurchaseReturnItemService returnItemService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpPurchaseReturnItemVo> list(ErpPurchaseReturnItemBo bo, PageQuery pageQuery) {
|
||||
return returnItemService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "采购退货明细", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpPurchaseReturnItemBo bo, HttpServletResponse response) {
|
||||
List<ErpPurchaseReturnItemVo> list = returnItemService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "采购退货明细", ErpPurchaseReturnItemVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{returnItemId}")
|
||||
public R<ErpPurchaseReturnItemVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long returnItemId) {
|
||||
return R.ok(returnItemService.queryById(returnItemId));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货明细", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpPurchaseReturnItemBo bo) {
|
||||
return toAjax(returnItemService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货明细", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpPurchaseReturnItemBo bo) {
|
||||
return toAjax(returnItemService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "采购退货明细", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{returnItemIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] returnItemIds) {
|
||||
return toAjax(returnItemService.deleteWithValidByIds(Arrays.asList(returnItemIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpSupplierBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierVo;
|
||||
import com.klp.erp.service.IErpSupplierService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/supplier")
|
||||
public class ErpSupplierController extends BaseController {
|
||||
|
||||
private final IErpSupplierService supplierService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpSupplierVo> list(ErpSupplierBo bo, PageQuery pageQuery) {
|
||||
return supplierService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "供应商档案", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpSupplierBo bo, HttpServletResponse response) {
|
||||
List<ErpSupplierVo> list = supplierService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "供应商档案", ErpSupplierVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{supplierId}")
|
||||
public R<ErpSupplierVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long supplierId) {
|
||||
return R.ok(supplierService.queryById(supplierId));
|
||||
}
|
||||
|
||||
@Log(title = "供应商档案", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpSupplierBo bo) {
|
||||
return toAjax(supplierService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "供应商档案", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpSupplierBo bo) {
|
||||
return toAjax(supplierService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "供应商档案", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{supplierIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] supplierIds) {
|
||||
return toAjax(supplierService.deleteWithValidByIds(Arrays.asList(supplierIds), true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.klp.erp.controller;
|
||||
|
||||
import com.klp.common.annotation.Log;
|
||||
import com.klp.common.annotation.RepeatSubmit;
|
||||
import com.klp.common.core.controller.BaseController;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.domain.R;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import com.klp.common.enums.BusinessType;
|
||||
import com.klp.common.utils.poi.ExcelUtil;
|
||||
import com.klp.erp.domain.bo.ErpSupplierPriceBo;
|
||||
import com.klp.erp.domain.bo.MaterialTypeQueryBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierPriceVo;
|
||||
import com.klp.erp.domain.vo.MaterialTypeOptionVo;
|
||||
import com.klp.erp.service.IErpSupplierPriceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Validated
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/erp/supplierPrice")
|
||||
public class ErpSupplierPriceController extends BaseController {
|
||||
|
||||
private final IErpSupplierPriceService supplierPriceService;
|
||||
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo<ErpSupplierPriceVo> list(ErpSupplierPriceBo bo, PageQuery pageQuery) {
|
||||
return supplierPriceService.queryPageList(bo, pageQuery);
|
||||
}
|
||||
|
||||
@Log(title = "供应商价格", businessType = BusinessType.EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(ErpSupplierPriceBo bo, HttpServletResponse response) {
|
||||
List<ErpSupplierPriceVo> list = supplierPriceService.queryList(bo);
|
||||
ExcelUtil.exportExcel(list, "供应商价格", ErpSupplierPriceVo.class, response);
|
||||
}
|
||||
|
||||
@GetMapping("/{priceId}")
|
||||
public R<ErpSupplierPriceVo> getInfo(@NotNull(message = "主键不能为空")
|
||||
@PathVariable Long priceId) {
|
||||
return R.ok(supplierPriceService.queryById(priceId));
|
||||
}
|
||||
|
||||
@Log(title = "供应商价格", businessType = BusinessType.INSERT)
|
||||
@RepeatSubmit
|
||||
@PostMapping
|
||||
public R<Void> add(@Validated(AddGroup.class) @RequestBody ErpSupplierPriceBo bo) {
|
||||
return toAjax(supplierPriceService.insertByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "供应商价格", businessType = BusinessType.UPDATE)
|
||||
@RepeatSubmit
|
||||
@PutMapping
|
||||
public R<Void> edit(@Validated(EditGroup.class) @RequestBody ErpSupplierPriceBo bo) {
|
||||
return toAjax(supplierPriceService.updateByBo(bo));
|
||||
}
|
||||
|
||||
@Log(title = "供应商价格", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/{priceIds}")
|
||||
public R<Void> remove(@NotEmpty(message = "主键不能为空")
|
||||
@PathVariable Long[] priceIds) {
|
||||
return toAjax(supplierPriceService.deleteWithValidByIds(Arrays.asList(priceIds), true));
|
||||
}
|
||||
|
||||
/**
|
||||
* 物料类型下拉
|
||||
*/
|
||||
@GetMapping("/material-types")
|
||||
public R<List<MaterialTypeOptionVo>> materialTypes(MaterialTypeQueryBo bo) {
|
||||
return R.ok(supplierPriceService.queryMaterialTypeOptions(bo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 采购订单明细对象 erp_purchase_order_item
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_purchase_order_item")
|
||||
public class ErpPurchaseOrderItem extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "item_id")
|
||||
private Long itemId;
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
private BigDecimal quantity;
|
||||
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private BigDecimal currentStock;
|
||||
|
||||
private BigDecimal onTheWay;
|
||||
|
||||
private BigDecimal salesDemand;
|
||||
|
||||
private BigDecimal suggestPurchase;
|
||||
|
||||
@TableLogic
|
||||
private Long delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 采购收货记录表 erp_purchase_receipt
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_purchase_receipt")
|
||||
public class ErpPurchaseReceipt extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "receipt_id")
|
||||
private Long receiptId;
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private Long itemId;
|
||||
|
||||
private BigDecimal receivedQty;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date receiptTime;
|
||||
|
||||
private String qualityResult;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_purchase_requirement")
|
||||
public class ErpPurchaseRequirement extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "req_id")
|
||||
private Long reqId;
|
||||
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
private BigDecimal salesDemand;
|
||||
|
||||
private BigDecimal productStock;
|
||||
|
||||
private BigDecimal rawStock;
|
||||
|
||||
private BigDecimal rawStockConv;
|
||||
|
||||
private BigDecimal onTheWay;
|
||||
|
||||
private BigDecimal onTheWayConv;
|
||||
|
||||
private BigDecimal suggestPurchaseQty;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 采购退货主表 erp_purchase_return
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_purchase_return")
|
||||
public class ErpPurchaseReturn extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "return_id")
|
||||
private Long returnId;
|
||||
|
||||
private Long orderId;
|
||||
|
||||
private String returnType;
|
||||
|
||||
private String reason;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 采购退货明细表 erp_purchase_return_item
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_purchase_return_item")
|
||||
public class ErpPurchaseReturnItem extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "return_item_id")
|
||||
private Long returnItemId;
|
||||
|
||||
private Long returnId;
|
||||
|
||||
private Long itemId;
|
||||
|
||||
private BigDecimal returnQty;
|
||||
|
||||
private String photos;
|
||||
|
||||
@TableLogic
|
||||
private Integer delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
44
klp-erp/src/main/java/com/klp/erp/domain/ErpSupplier.java
Normal file
44
klp-erp/src/main/java/com/klp/erp/domain/ErpSupplier.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 供应商档案对象 erp_supplier
|
||||
*
|
||||
* @author klp
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_supplier")
|
||||
public class ErpSupplier extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "supplier_id")
|
||||
private Long supplierId;
|
||||
|
||||
private String supplierCode;
|
||||
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String creditRating;
|
||||
|
||||
private String contactPerson;
|
||||
|
||||
private String contactPhone;
|
||||
|
||||
private String address;
|
||||
|
||||
@TableLogic
|
||||
private Long delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.klp.erp.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 供应商价格对象 erp_supplier_price
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName("erp_supplier_price")
|
||||
public class ErpSupplierPrice extends BaseEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "price_id")
|
||||
private Long priceId;
|
||||
|
||||
private Long supplierId;
|
||||
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
private BigDecimal price;
|
||||
|
||||
private Date validFrom;
|
||||
|
||||
private Date validTo;
|
||||
|
||||
@TableLogic
|
||||
private Long delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 采购订单明细业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpPurchaseOrderItemBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long itemId;
|
||||
|
||||
@NotNull(message = "订单ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long orderId;
|
||||
|
||||
@NotBlank(message = "物料类型编码不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
@NotNull(message = "采购数量不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private BigDecimal quantity;
|
||||
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private BigDecimal currentStock;
|
||||
|
||||
private BigDecimal onTheWay;
|
||||
|
||||
private BigDecimal salesDemand;
|
||||
|
||||
private BigDecimal suggestPurchase;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpPurchaseReceiptBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long receiptId;
|
||||
|
||||
@NotNull(message = "订单ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long orderId;
|
||||
|
||||
@NotNull(message = "订单明细ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long itemId;
|
||||
|
||||
@NotNull(message = "收货数量不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private BigDecimal receivedQty;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date receiptTime;
|
||||
|
||||
private String qualityResult;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpPurchaseReturnBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long returnId;
|
||||
|
||||
@NotNull(message = "订单ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long orderId;
|
||||
|
||||
private String returnType;
|
||||
|
||||
private String reason;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpPurchaseReturnItemBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long returnItemId;
|
||||
|
||||
@NotNull(message = "退货单ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long returnId;
|
||||
|
||||
@NotNull(message = "订单明细ID不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long itemId;
|
||||
|
||||
@NotNull(message = "退货数量不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private BigDecimal returnQty;
|
||||
|
||||
private String photos;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 供应商档案业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpSupplierBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long supplierId;
|
||||
|
||||
@NotBlank(message = "供应商编码不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String supplierCode;
|
||||
|
||||
@NotBlank(message = "供应商名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String name;
|
||||
|
||||
private String type;
|
||||
|
||||
private String creditRating;
|
||||
|
||||
private String contactPerson;
|
||||
|
||||
private String contactPhone;
|
||||
|
||||
private String address;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import com.klp.common.core.validate.AddGroup;
|
||||
import com.klp.common.core.validate.EditGroup;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 供应商价格业务对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ErpSupplierPriceBo extends BaseEntity {
|
||||
|
||||
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
|
||||
private Long priceId;
|
||||
|
||||
@NotNull(message = "供应商不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private Long supplierId;
|
||||
|
||||
@NotBlank(message = "物料类型不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
@NotNull(message = "价格不能为空", groups = {AddGroup.class, EditGroup.class})
|
||||
private BigDecimal price;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date validFrom;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date validTo;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import com.klp.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 物料类型查询条件
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class MaterialTypeQueryBo extends BaseEntity {
|
||||
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
private Long supplierId;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PurchaseRequirementAnalyzeBo {
|
||||
|
||||
/**
|
||||
* 产品与原料转换关系
|
||||
*/
|
||||
@NotEmpty(message = "转换映射关系不能为空")
|
||||
@Valid
|
||||
private List<PurchaseRequirementMappingBo> mappings;
|
||||
|
||||
/**
|
||||
* 是否持久化分析结果
|
||||
*/
|
||||
private Boolean persistResult = Boolean.FALSE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.klp.erp.domain.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class PurchaseRequirementMappingBo {
|
||||
|
||||
@NotNull(message = "产品ID不能为空")
|
||||
private Long productId;
|
||||
|
||||
private String productCode;
|
||||
|
||||
@NotNull(message = "原料ID不能为空")
|
||||
private Long rawMaterialId;
|
||||
|
||||
private String rawMaterialCode;
|
||||
|
||||
/**
|
||||
* 原料转成品的转换率(0.95 表示 1 吨原料 ≈ 0.95 吨成品)
|
||||
*/
|
||||
@NotNull(message = "转换率不能为空")
|
||||
private BigDecimal conversionRate;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ProductDemandDTO {
|
||||
private Long productId;
|
||||
private BigDecimal demandQuantity;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.klp.erp.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class ProductStockDTO {
|
||||
private Long productId;
|
||||
private Long coilCount;
|
||||
private BigDecimal totalWeight;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.klp.erp.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class RawStockDTO {
|
||||
private Long rawMaterialId;
|
||||
private Long coilCount;
|
||||
private BigDecimal totalWeight;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class RawTransitDTO {
|
||||
private Long rawMaterialId;
|
||||
private BigDecimal quantity;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 采购订单明细视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpPurchaseOrderItemVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("明细ID")
|
||||
private Long itemId;
|
||||
|
||||
@ExcelProperty("订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@ExcelProperty("物料类型编码")
|
||||
private String materialTypeCode;
|
||||
|
||||
@ExcelProperty("规格")
|
||||
private String specification;
|
||||
|
||||
@ExcelProperty("采购数量")
|
||||
private BigDecimal quantity;
|
||||
|
||||
@ExcelProperty("单价")
|
||||
private BigDecimal unitPrice;
|
||||
|
||||
@ExcelProperty("金额")
|
||||
private BigDecimal amount;
|
||||
|
||||
@ExcelProperty("当前库存")
|
||||
private BigDecimal currentStock;
|
||||
|
||||
@ExcelProperty("在途数量")
|
||||
private BigDecimal onTheWay;
|
||||
|
||||
@ExcelProperty("销售需求")
|
||||
private BigDecimal salesDemand;
|
||||
|
||||
@ExcelProperty("建议采购数量")
|
||||
private BigDecimal suggestPurchase;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpPurchaseReceiptVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("收货记录ID")
|
||||
private Long receiptId;
|
||||
|
||||
@ExcelProperty("订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@ExcelProperty("订单明细ID")
|
||||
private Long itemId;
|
||||
|
||||
@ExcelProperty("收货数量")
|
||||
private BigDecimal receivedQty;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ExcelProperty("收货时间")
|
||||
private Date receiptTime;
|
||||
|
||||
@ExcelProperty("质检结果")
|
||||
private String qualityResult;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpPurchaseReturnItemVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("退货明细ID")
|
||||
private Long returnItemId;
|
||||
|
||||
@ExcelProperty("退货单ID")
|
||||
private Long returnId;
|
||||
|
||||
@ExcelProperty("订单明细ID")
|
||||
private Long itemId;
|
||||
|
||||
@ExcelProperty("退货数量")
|
||||
private BigDecimal returnQty;
|
||||
|
||||
@ExcelProperty("问题照片")
|
||||
private String photos;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpPurchaseReturnVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("退货单ID")
|
||||
private Long returnId;
|
||||
|
||||
@ExcelProperty("订单ID")
|
||||
private Long orderId;
|
||||
|
||||
@ExcelProperty("退货类型")
|
||||
private String returnType;
|
||||
|
||||
@ExcelProperty("退货原因")
|
||||
private String reason;
|
||||
|
||||
@ExcelProperty("退货状态")
|
||||
private Integer status;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 供应商价格视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpSupplierPriceVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("价格ID")
|
||||
private Long priceId;
|
||||
|
||||
@ExcelProperty("供应商ID")
|
||||
private Long supplierId;
|
||||
|
||||
@ExcelProperty("物料类型编码")
|
||||
private String materialTypeCode;
|
||||
|
||||
@ExcelProperty("规格")
|
||||
private String specification;
|
||||
|
||||
@ExcelProperty("价格")
|
||||
private BigDecimal price;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@ExcelProperty("生效日期")
|
||||
private Date validFrom;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@ExcelProperty("失效日期")
|
||||
private Date validTo;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import com.alibaba.excel.annotation.ExcelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 供应商档案视图对象
|
||||
*/
|
||||
@Data
|
||||
@ExcelIgnoreUnannotated
|
||||
public class ErpSupplierVo implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ExcelProperty("供应商ID")
|
||||
private Long supplierId;
|
||||
|
||||
@ExcelProperty("供应商编码")
|
||||
private String supplierCode;
|
||||
|
||||
@ExcelProperty("供应商名称")
|
||||
private String name;
|
||||
|
||||
@ExcelProperty("供应商类型")
|
||||
private String type;
|
||||
|
||||
@ExcelProperty("信用等级")
|
||||
private String creditRating;
|
||||
|
||||
@ExcelProperty("联系人")
|
||||
private String contactPerson;
|
||||
|
||||
@ExcelProperty("联系电话")
|
||||
private String contactPhone;
|
||||
|
||||
@ExcelProperty("地址")
|
||||
private String address;
|
||||
|
||||
@ExcelProperty("备注")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 物料类型下拉视图
|
||||
*/
|
||||
@Data
|
||||
public class MaterialTypeOptionVo {
|
||||
|
||||
private String materialTypeCode;
|
||||
|
||||
private String specification;
|
||||
|
||||
private Long supplierId;
|
||||
|
||||
private String supplierName;
|
||||
|
||||
private java.math.BigDecimal latestPrice;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
public class PurchaseRequirementRawDetailVo {
|
||||
private Long rawMaterialId;
|
||||
private String rawMaterialCode;
|
||||
private String rawMaterialName;
|
||||
private BigDecimal conversionRate;
|
||||
private BigDecimal stockWeight;
|
||||
private Long stockCoilCount;
|
||||
private BigDecimal inTransitWeight;
|
||||
private BigDecimal pendingWeight;
|
||||
private BigDecimal convertedStock;
|
||||
private BigDecimal convertedInTransit;
|
||||
private BigDecimal convertedPending;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.klp.erp.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PurchaseRequirementVo {
|
||||
private Long productId;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
private String specification;
|
||||
|
||||
private BigDecimal salesDemand = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal productStockWeight = BigDecimal.ZERO;
|
||||
private Long productStockCoilCount = 0L;
|
||||
|
||||
private BigDecimal rawStockWeight = BigDecimal.ZERO;
|
||||
private Long rawStockCoilCount = 0L;
|
||||
private BigDecimal rawStockConverted = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal inTransitWeight = BigDecimal.ZERO;
|
||||
private BigDecimal inTransitConverted = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal pendingWeight = BigDecimal.ZERO;
|
||||
private BigDecimal pendingConverted = BigDecimal.ZERO;
|
||||
|
||||
private BigDecimal suggestedPurchase = BigDecimal.ZERO;
|
||||
|
||||
private List<PurchaseRequirementRawDetailVo> rawDetails = new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.klp.erp.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 采购订单状态枚举
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum PurchaseOrderStatus {
|
||||
|
||||
DRAFT(0),
|
||||
EXECUTING(1),
|
||||
PARTIAL_ARRIVAL(2),
|
||||
COMPLETED(3),
|
||||
CANCELLED(4);
|
||||
|
||||
private final int code;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpPurchaseOrderItem;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseOrderItemVo;
|
||||
|
||||
/**
|
||||
* 采购订单明细Mapper接口
|
||||
*/
|
||||
public interface ErpPurchaseOrderItemMapper extends BaseMapperPlus<ErpPurchaseOrderItemMapper, ErpPurchaseOrderItem, ErpPurchaseOrderItemVo> {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpPurchaseReceipt;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReceiptVo;
|
||||
|
||||
public interface ErpPurchaseReceiptMapper extends BaseMapperPlus<ErpPurchaseReceiptMapper, ErpPurchaseReceipt, ErpPurchaseReceiptVo> {
|
||||
|
||||
java.math.BigDecimal sumQualifiedQtyByItem(Long itemId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface ErpPurchaseReportMapper {
|
||||
|
||||
BigDecimal sumTotalAmount(@Param("beginTime") String beginTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
List<Map<String, Object>> sumAmountBySupplier(@Param("beginTime") String beginTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
List<Map<String, Object>> selectPriceTrend(@Param("beginTime") String beginTime,
|
||||
@Param("endTime") String endTime);
|
||||
|
||||
List<Map<String, Object>> selectSupplierQuality(@Param("beginTime") String beginTime,
|
||||
@Param("endTime") String endTime);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpPurchaseRequirement;
|
||||
import org.apache.ibatis.annotations.Delete;
|
||||
|
||||
public interface ErpPurchaseRequirementMapper extends BaseMapperPlus<ErpPurchaseRequirementMapper, ErpPurchaseRequirement, ErpPurchaseRequirement> {
|
||||
|
||||
@Delete("DELETE FROM erp_purchase_requirement")
|
||||
void deleteAll();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpPurchaseReturnItem;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnItemVo;
|
||||
|
||||
public interface ErpPurchaseReturnItemMapper extends BaseMapperPlus<ErpPurchaseReturnItemMapper, ErpPurchaseReturnItem, ErpPurchaseReturnItemVo> {
|
||||
|
||||
java.math.BigDecimal sumAllReturnQtyByItem(Long itemId);
|
||||
|
||||
java.math.BigDecimal sumCompletedReturnQtyByItem(Long itemId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpPurchaseReturn;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnVo;
|
||||
|
||||
public interface ErpPurchaseReturnMapper extends BaseMapperPlus<ErpPurchaseReturnMapper, ErpPurchaseReturn, ErpPurchaseReturnVo> {
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpSupplier;
|
||||
import com.klp.erp.domain.vo.ErpSupplierVo;
|
||||
|
||||
/**
|
||||
* 供应商档案Mapper接口
|
||||
*/
|
||||
public interface ErpSupplierMapper extends BaseMapperPlus<ErpSupplierMapper, ErpSupplier, ErpSupplierVo> {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.common.core.mapper.BaseMapperPlus;
|
||||
import com.klp.erp.domain.ErpSupplierPrice;
|
||||
import com.klp.erp.domain.bo.MaterialTypeQueryBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierPriceVo;
|
||||
import com.klp.erp.domain.vo.MaterialTypeOptionVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 供应商价格Mapper接口
|
||||
*/
|
||||
public interface ErpSupplierPriceMapper extends BaseMapperPlus<ErpSupplierPriceMapper, ErpSupplierPrice, ErpSupplierPriceVo> {
|
||||
|
||||
List<MaterialTypeOptionVo> selectMaterialTypeOptions(MaterialTypeQueryBo bo);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.klp.erp.mapper;
|
||||
|
||||
import com.klp.erp.domain.dto.ProductDemandDTO;
|
||||
import com.klp.erp.domain.dto.ProductStockDTO;
|
||||
import com.klp.erp.domain.dto.RawStockDTO;
|
||||
import com.klp.erp.domain.dto.RawTransitDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface PurchaseRequirementCalcMapper {
|
||||
|
||||
List<ProductDemandDTO> selectProductDemand();
|
||||
|
||||
List<ProductStockDTO> selectProductStock();
|
||||
|
||||
List<RawStockDTO> selectRawStock();
|
||||
|
||||
List<RawTransitDTO> selectRawInTransit();
|
||||
|
||||
List<RawTransitDTO> selectRawPending();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseOrderItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseOrderItemVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 采购订单明细Service接口
|
||||
*/
|
||||
public interface IErpPurchaseOrderItemService {
|
||||
|
||||
ErpPurchaseOrderItemVo queryById(Long itemId);
|
||||
|
||||
TableDataInfo<ErpPurchaseOrderItemVo> queryPageList(ErpPurchaseOrderItemBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpPurchaseOrderItemVo> queryList(ErpPurchaseOrderItemBo bo);
|
||||
|
||||
Boolean insertByBo(ErpPurchaseOrderItemBo bo);
|
||||
|
||||
Boolean updateByBo(ErpPurchaseOrderItemBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReceiptBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReceiptVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IErpPurchaseReceiptService {
|
||||
|
||||
ErpPurchaseReceiptVo queryById(Long receiptId);
|
||||
|
||||
TableDataInfo<ErpPurchaseReceiptVo> queryPageList(ErpPurchaseReceiptBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpPurchaseReceiptVo> queryList(ErpPurchaseReceiptBo bo);
|
||||
|
||||
Boolean insertByBo(ErpPurchaseReceiptBo bo);
|
||||
|
||||
Boolean updateByBo(ErpPurchaseReceiptBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.erp.domain.bo.PurchaseRequirementAnalyzeBo;
|
||||
import com.klp.erp.domain.vo.PurchaseRequirementVo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IErpPurchaseRequirementService {
|
||||
|
||||
List<PurchaseRequirementVo> analyze(PurchaseRequirementAnalyzeBo bo);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnItemVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IErpPurchaseReturnItemService {
|
||||
|
||||
ErpPurchaseReturnItemVo queryById(Long returnItemId);
|
||||
|
||||
TableDataInfo<ErpPurchaseReturnItemVo> queryPageList(ErpPurchaseReturnItemBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpPurchaseReturnItemVo> queryList(ErpPurchaseReturnItemBo bo);
|
||||
|
||||
Boolean insertByBo(ErpPurchaseReturnItemBo bo);
|
||||
|
||||
Boolean updateByBo(ErpPurchaseReturnItemBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface IErpPurchaseReturnService {
|
||||
|
||||
ErpPurchaseReturnVo queryById(Long returnId);
|
||||
|
||||
TableDataInfo<ErpPurchaseReturnVo> queryPageList(ErpPurchaseReturnBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpPurchaseReturnVo> queryList(ErpPurchaseReturnBo bo);
|
||||
|
||||
Boolean insertByBo(ErpPurchaseReturnBo bo);
|
||||
|
||||
Boolean updateByBo(ErpPurchaseReturnBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpSupplierPriceBo;
|
||||
import com.klp.erp.domain.bo.MaterialTypeQueryBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierPriceVo;
|
||||
import com.klp.erp.domain.vo.MaterialTypeOptionVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 供应商价格Service接口
|
||||
*/
|
||||
public interface IErpSupplierPriceService {
|
||||
|
||||
ErpSupplierPriceVo queryById(Long priceId);
|
||||
|
||||
TableDataInfo<ErpSupplierPriceVo> queryPageList(ErpSupplierPriceBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpSupplierPriceVo> queryList(ErpSupplierPriceBo bo);
|
||||
|
||||
Boolean insertByBo(ErpSupplierPriceBo bo);
|
||||
|
||||
Boolean updateByBo(ErpSupplierPriceBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
|
||||
List<MaterialTypeOptionVo> queryMaterialTypeOptions(MaterialTypeQueryBo bo);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.klp.erp.service;
|
||||
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.bo.ErpSupplierBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierVo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 供应商档案Service接口
|
||||
*/
|
||||
public interface IErpSupplierService {
|
||||
|
||||
ErpSupplierVo queryById(Long supplierId);
|
||||
|
||||
TableDataInfo<ErpSupplierVo> queryPageList(ErpSupplierBo bo, PageQuery pageQuery);
|
||||
|
||||
List<ErpSupplierVo> queryList(ErpSupplierBo bo);
|
||||
|
||||
Boolean insertByBo(ErpSupplierBo bo);
|
||||
|
||||
Boolean updateByBo(ErpSupplierBo bo);
|
||||
|
||||
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.erp.domain.ErpPurchaseOrderItem;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseOrderItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseOrderItemVo;
|
||||
import com.klp.erp.mapper.ErpPurchaseOrderItemMapper;
|
||||
import com.klp.erp.service.IErpPurchaseOrderItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ErpPurchaseOrderItemServiceImpl implements IErpPurchaseOrderItemService {
|
||||
|
||||
private final ErpPurchaseOrderItemMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public ErpPurchaseOrderItemVo queryById(Long itemId) {
|
||||
return baseMapper.selectVoById(itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpPurchaseOrderItemVo> queryPageList(ErpPurchaseOrderItemBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpPurchaseOrderItem> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpPurchaseOrderItemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpPurchaseOrderItemVo> queryList(ErpPurchaseOrderItemBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseOrderItem> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpPurchaseOrderItem> buildQueryWrapper(ErpPurchaseOrderItemBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseOrderItem> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getOrderId() != null, ErpPurchaseOrderItem::getOrderId, bo.getOrderId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMaterialTypeCode()), ErpPurchaseOrderItem::getMaterialTypeCode, bo.getMaterialTypeCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getSpecification()), ErpPurchaseOrderItem::getSpecification, bo.getSpecification());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpPurchaseOrderItemBo bo) {
|
||||
ErpPurchaseOrderItem add = BeanUtil.toBean(bo, ErpPurchaseOrderItem.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setItemId(add.getItemId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpPurchaseOrderItemBo bo) {
|
||||
ErpPurchaseOrderItem update = BeanUtil.toBean(bo, ErpPurchaseOrderItem.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ErpPurchaseOrderItem entity) {
|
||||
// TODO: 数量/金额校验
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 删除校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.erp.domain.ErpPurchaseOrderItem;
|
||||
import com.klp.erp.domain.ErpPurchaseReceipt;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReceiptBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReceiptVo;
|
||||
import com.klp.erp.mapper.ErpPurchaseOrderItemMapper;
|
||||
import com.klp.erp.mapper.ErpPurchaseReceiptMapper;
|
||||
import com.klp.erp.service.IErpPurchaseOrderService;
|
||||
import com.klp.erp.service.IErpPurchaseReceiptService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ErpPurchaseReceiptServiceImpl implements IErpPurchaseReceiptService {
|
||||
|
||||
private final ErpPurchaseReceiptMapper baseMapper;
|
||||
private final ErpPurchaseOrderItemMapper orderItemMapper;
|
||||
private final IErpPurchaseOrderService orderService;
|
||||
|
||||
@Override
|
||||
public ErpPurchaseReceiptVo queryById(Long receiptId) {
|
||||
return baseMapper.selectVoById(receiptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpPurchaseReceiptVo> queryPageList(ErpPurchaseReceiptBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpPurchaseReceipt> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpPurchaseReceiptVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpPurchaseReceiptVo> queryList(ErpPurchaseReceiptBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReceipt> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpPurchaseReceipt> buildQueryWrapper(ErpPurchaseReceiptBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReceipt> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getOrderId() != null, ErpPurchaseReceipt::getOrderId, bo.getOrderId());
|
||||
lqw.eq(bo.getItemId() != null, ErpPurchaseReceipt::getItemId, bo.getItemId());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpPurchaseReceiptBo bo) {
|
||||
ErpPurchaseReceipt add = BeanUtil.toBean(bo, ErpPurchaseReceipt.class);
|
||||
validateReceiptQuantity(null, bo);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setReceiptId(add.getReceiptId());
|
||||
if (isQualified(bo.getQualityResult())) {
|
||||
orderService.refreshOrderStatus(bo.getOrderId());
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpPurchaseReceiptBo bo) {
|
||||
ErpPurchaseReceipt origin = baseMapper.selectById(bo.getReceiptId());
|
||||
if (origin == null) {
|
||||
throw new ServiceException("收货记录不存在");
|
||||
}
|
||||
ErpPurchaseReceipt update = BeanUtil.toBean(bo, ErpPurchaseReceipt.class);
|
||||
validateReceiptQuantity(origin, bo);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
if (flag) {
|
||||
orderService.refreshOrderStatus(origin.getOrderId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void validateReceiptQuantity(ErpPurchaseReceipt origin, ErpPurchaseReceiptBo bo) {
|
||||
ErpPurchaseOrderItem item = orderItemMapper.selectById(bo.getItemId());
|
||||
if (item == null) {
|
||||
throw new ServiceException("订单明细不存在");
|
||||
}
|
||||
if (!item.getOrderId().equals(bo.getOrderId())) {
|
||||
throw new ServiceException("订单与明细不匹配");
|
||||
}
|
||||
BigDecimal ordered = safe(item.getQuantity());
|
||||
BigDecimal existingQualified = safe(baseMapper.sumQualifiedQtyByItem(bo.getItemId()));
|
||||
BigDecimal originQualified = origin != null && isQualified(origin.getQualityResult())
|
||||
? safe(origin.getReceivedQty()) : BigDecimal.ZERO;
|
||||
BigDecimal newQualified = isQualified(bo.getQualityResult()) ? safe(bo.getReceivedQty()) : BigDecimal.ZERO;
|
||||
BigDecimal effective = existingQualified.subtract(originQualified).add(newQualified);
|
||||
if (effective.compareTo(ordered) > 0) {
|
||||
throw new ServiceException("收货数量不能超过订单明细数量");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
List<ErpPurchaseReceipt> receipts = baseMapper.selectBatchIds(ids);
|
||||
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
|
||||
if (flag && receipts != null && !receipts.isEmpty()) {
|
||||
Set<Long> orderIds = new HashSet<>();
|
||||
for (ErpPurchaseReceipt receipt : receipts) {
|
||||
orderIds.add(receipt.getOrderId());
|
||||
}
|
||||
orderIds.forEach(orderService::refreshOrderStatus);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
private boolean isQualified(String qualityResult) {
|
||||
if (qualityResult == null) {
|
||||
return true;
|
||||
}
|
||||
String upper = qualityResult.trim().toUpperCase();
|
||||
return !"NG".equals(upper) && !"不合格".equals(qualityResult.trim());
|
||||
}
|
||||
|
||||
private BigDecimal safe(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO : value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.klp.domain.WmsProduct;
|
||||
import com.klp.domain.WmsRawMaterial;
|
||||
import com.klp.erp.domain.ErpPurchaseRequirement;
|
||||
import com.klp.erp.domain.bo.PurchaseRequirementAnalyzeBo;
|
||||
import com.klp.erp.domain.bo.PurchaseRequirementMappingBo;
|
||||
import com.klp.erp.domain.dto.ProductDemandDTO;
|
||||
import com.klp.erp.domain.dto.ProductStockDTO;
|
||||
import com.klp.erp.domain.dto.RawStockDTO;
|
||||
import com.klp.erp.domain.dto.RawTransitDTO;
|
||||
import com.klp.erp.domain.vo.PurchaseRequirementRawDetailVo;
|
||||
import com.klp.erp.domain.vo.PurchaseRequirementVo;
|
||||
import com.klp.erp.mapper.ErpPurchaseRequirementMapper;
|
||||
import com.klp.erp.mapper.PurchaseRequirementCalcMapper;
|
||||
import com.klp.erp.service.IErpPurchaseRequirementService;
|
||||
import com.klp.mapper.WmsProductMapper;
|
||||
import com.klp.mapper.WmsRawMaterialMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ErpPurchaseRequirementServiceImpl implements IErpPurchaseRequirementService {
|
||||
|
||||
private static final BigDecimal ZERO = BigDecimal.ZERO;
|
||||
|
||||
private final PurchaseRequirementCalcMapper calcMapper;
|
||||
private final ErpPurchaseRequirementMapper requirementMapper;
|
||||
private final WmsProductMapper productMapper;
|
||||
private final WmsRawMaterialMapper rawMaterialMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public List<PurchaseRequirementVo> analyze(PurchaseRequirementAnalyzeBo bo) {
|
||||
Map<Long, List<PurchaseRequirementMappingBo>> mappingByProduct = bo.getMappings()
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(PurchaseRequirementMappingBo::getProductId));
|
||||
|
||||
Set<Long> productIds = new HashSet<>(mappingByProduct.keySet());
|
||||
Set<Long> rawIds = bo.getMappings().stream().map(PurchaseRequirementMappingBo::getRawMaterialId).collect(Collectors.toSet());
|
||||
|
||||
Map<Long, BigDecimal> demandMap = toBigDecimalMap(streamOf(calcMapper.selectProductDemand()),
|
||||
ProductDemandDTO::getProductId, ProductDemandDTO::getDemandQuantity);
|
||||
|
||||
productIds.addAll(demandMap.keySet());
|
||||
|
||||
Map<Long, ProductStockDTO> productStockMap = streamOf(calcMapper.selectProductStock())
|
||||
.collect(Collectors.toMap(ProductStockDTO::getProductId, Function.identity(), (a, b) -> a));
|
||||
|
||||
Map<Long, RawStockDTO> rawStockMap = streamOf(calcMapper.selectRawStock())
|
||||
.collect(Collectors.toMap(RawStockDTO::getRawMaterialId, Function.identity(), (a, b) -> a));
|
||||
|
||||
Map<Long, BigDecimal> rawInTransitMap = toBigDecimalMap(streamOf(calcMapper.selectRawInTransit()),
|
||||
RawTransitDTO::getRawMaterialId, RawTransitDTO::getQuantity);
|
||||
Map<Long, BigDecimal> rawPendingMap = toBigDecimalMap(streamOf(calcMapper.selectRawPending()),
|
||||
RawTransitDTO::getRawMaterialId, RawTransitDTO::getQuantity);
|
||||
|
||||
Map<Long, WmsProduct> productInfoMap = loadProducts(productIds);
|
||||
Map<Long, WmsRawMaterial> rawInfoMap = loadRawMaterials(rawIds);
|
||||
|
||||
List<PurchaseRequirementVo> result = productIds.stream()
|
||||
.sorted()
|
||||
.map(productId -> buildRequirement(productId,
|
||||
mappingByProduct.getOrDefault(productId, Collections.emptyList()),
|
||||
demandMap,
|
||||
productStockMap,
|
||||
rawStockMap,
|
||||
rawInTransitMap,
|
||||
rawPendingMap,
|
||||
productInfoMap,
|
||||
rawInfoMap))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (Boolean.TRUE.equals(bo.getPersistResult())) {
|
||||
persistRequirements(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private PurchaseRequirementVo buildRequirement(Long productId,
|
||||
List<PurchaseRequirementMappingBo> mappings,
|
||||
Map<Long, BigDecimal> demandMap,
|
||||
Map<Long, ProductStockDTO> productStockMap,
|
||||
Map<Long, RawStockDTO> rawStockMap,
|
||||
Map<Long, BigDecimal> rawInTransitMap,
|
||||
Map<Long, BigDecimal> rawPendingMap,
|
||||
Map<Long, WmsProduct> productInfoMap,
|
||||
Map<Long, WmsRawMaterial> rawInfoMap) {
|
||||
PurchaseRequirementVo vo = new PurchaseRequirementVo();
|
||||
vo.setProductId(productId);
|
||||
WmsProduct product = productInfoMap.get(productId);
|
||||
if (product != null) {
|
||||
vo.setProductCode(product.getProductCode());
|
||||
vo.setProductName(product.getProductName());
|
||||
vo.setSpecification(product.getSpecification());
|
||||
}
|
||||
vo.setSalesDemand(safeNumber(demandMap.get(productId)));
|
||||
|
||||
ProductStockDTO stockDTO = productStockMap.get(productId);
|
||||
if (stockDTO != null) {
|
||||
vo.setProductStockWeight(safeNumber(stockDTO.getTotalWeight()));
|
||||
vo.setProductStockCoilCount(Optional.ofNullable(stockDTO.getCoilCount()).orElse(0L));
|
||||
}
|
||||
|
||||
BigDecimal rawStockWeightSum = ZERO;
|
||||
long rawCoilCountSum = 0L;
|
||||
BigDecimal rawStockConvertedSum = ZERO;
|
||||
BigDecimal inTransitWeightSum = ZERO;
|
||||
BigDecimal inTransitConvertedSum = ZERO;
|
||||
BigDecimal pendingWeightSum = ZERO;
|
||||
BigDecimal pendingConvertedSum = ZERO;
|
||||
|
||||
for (PurchaseRequirementMappingBo mapping : mappings) {
|
||||
WmsRawMaterial rawMaterial = rawInfoMap.get(mapping.getRawMaterialId());
|
||||
if (rawMaterial == null) {
|
||||
continue;
|
||||
}
|
||||
PurchaseRequirementRawDetailVo detail = new PurchaseRequirementRawDetailVo();
|
||||
detail.setRawMaterialId(rawMaterial.getRawMaterialId());
|
||||
detail.setRawMaterialCode(rawMaterial.getRawMaterialCode());
|
||||
detail.setRawMaterialName(rawMaterial.getRawMaterialName());
|
||||
detail.setConversionRate(mapping.getConversionRate());
|
||||
|
||||
RawStockDTO rawStock = rawStockMap.get(rawMaterial.getRawMaterialId());
|
||||
BigDecimal stockWeight = rawStock == null ? ZERO : safeNumber(rawStock.getTotalWeight());
|
||||
long stockCoilCount = rawStock == null ? 0L : Optional.ofNullable(rawStock.getCoilCount()).orElse(0L);
|
||||
BigDecimal convertedStock = stockWeight.multiply(mapping.getConversionRate()).setScale(4, RoundingMode.HALF_UP);
|
||||
|
||||
BigDecimal inTransitWeight = safeNumber(rawInTransitMap.get(rawMaterial.getRawMaterialId()));
|
||||
BigDecimal convertedTransit = inTransitWeight.multiply(mapping.getConversionRate()).setScale(4, RoundingMode.HALF_UP);
|
||||
|
||||
BigDecimal pendingWeight = safeNumber(rawPendingMap.get(rawMaterial.getRawMaterialId()));
|
||||
BigDecimal convertedPending = pendingWeight.multiply(mapping.getConversionRate()).setScale(4, RoundingMode.HALF_UP);
|
||||
|
||||
detail.setStockWeight(stockWeight);
|
||||
detail.setStockCoilCount(stockCoilCount);
|
||||
detail.setConvertedStock(convertedStock);
|
||||
detail.setInTransitWeight(inTransitWeight);
|
||||
detail.setConvertedInTransit(convertedTransit);
|
||||
detail.setPendingWeight(pendingWeight);
|
||||
detail.setConvertedPending(convertedPending);
|
||||
vo.getRawDetails().add(detail);
|
||||
|
||||
rawStockWeightSum = rawStockWeightSum.add(stockWeight);
|
||||
rawCoilCountSum += stockCoilCount;
|
||||
rawStockConvertedSum = rawStockConvertedSum.add(convertedStock);
|
||||
inTransitWeightSum = inTransitWeightSum.add(inTransitWeight);
|
||||
inTransitConvertedSum = inTransitConvertedSum.add(convertedTransit);
|
||||
pendingWeightSum = pendingWeightSum.add(pendingWeight);
|
||||
pendingConvertedSum = pendingConvertedSum.add(convertedPending);
|
||||
}
|
||||
|
||||
vo.setRawStockWeight(rawStockWeightSum);
|
||||
vo.setRawStockCoilCount(rawCoilCountSum);
|
||||
vo.setRawStockConverted(rawStockConvertedSum);
|
||||
vo.setInTransitWeight(inTransitWeightSum);
|
||||
vo.setInTransitConverted(inTransitConvertedSum);
|
||||
vo.setPendingWeight(pendingWeightSum);
|
||||
vo.setPendingConverted(pendingConvertedSum);
|
||||
|
||||
BigDecimal suggestion = vo.getSalesDemand()
|
||||
.subtract(vo.getProductStockWeight())
|
||||
.subtract(vo.getRawStockConverted())
|
||||
.subtract(vo.getInTransitConverted())
|
||||
.subtract(vo.getPendingConverted());
|
||||
if (suggestion.signum() < 0) {
|
||||
suggestion = ZERO;
|
||||
}
|
||||
vo.setSuggestedPurchase(suggestion.setScale(4, RoundingMode.HALF_UP));
|
||||
return vo;
|
||||
}
|
||||
|
||||
private <T> Stream<T> streamOf(List<T> list) {
|
||||
return list == null ? Stream.empty() : list.stream();
|
||||
}
|
||||
|
||||
private BigDecimal safeNumber(BigDecimal value) {
|
||||
return value == null ? ZERO : value;
|
||||
}
|
||||
|
||||
private Map<Long, WmsProduct> loadProducts(Set<Long> ids) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<WmsProduct> list = productMapper.selectBatchIds(new ArrayList<>(ids));
|
||||
return list == null ? Collections.emptyMap() : list.stream()
|
||||
.collect(Collectors.toMap(WmsProduct::getProductId, Function.identity(), (a, b) -> a));
|
||||
}
|
||||
|
||||
private Map<Long, WmsRawMaterial> loadRawMaterials(Set<Long> ids) {
|
||||
if (CollectionUtils.isEmpty(ids)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
List<WmsRawMaterial> list = rawMaterialMapper.selectBatchIds(new ArrayList<>(ids));
|
||||
return list == null ? Collections.emptyMap() : list.stream()
|
||||
.collect(Collectors.toMap(WmsRawMaterial::getRawMaterialId, Function.identity(), (a, b) -> a));
|
||||
}
|
||||
|
||||
private void persistRequirements(List<PurchaseRequirementVo> vos) {
|
||||
requirementMapper.deleteAll();
|
||||
for (PurchaseRequirementVo vo : vos) {
|
||||
ErpPurchaseRequirement entity = new ErpPurchaseRequirement();
|
||||
entity.setMaterialTypeCode(vo.getProductCode());
|
||||
entity.setSpecification(vo.getSpecification());
|
||||
entity.setSalesDemand(vo.getSalesDemand());
|
||||
entity.setProductStock(vo.getProductStockWeight());
|
||||
entity.setRawStock(vo.getRawStockWeight());
|
||||
entity.setRawStockConv(vo.getRawStockConverted());
|
||||
entity.setOnTheWay(vo.getInTransitWeight());
|
||||
entity.setOnTheWayConv(vo.getInTransitConverted());
|
||||
entity.setSuggestPurchaseQty(vo.getSuggestedPurchase());
|
||||
entity.setRemark("自动分析");
|
||||
requirementMapper.insert(entity);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> Map<Long, BigDecimal> toBigDecimalMap(Stream<T> stream,
|
||||
Function<T, Long> keyExtractor,
|
||||
Function<T, BigDecimal> valueExtractor) {
|
||||
return stream == null ? Collections.emptyMap()
|
||||
: stream.filter(Objects::nonNull)
|
||||
.collect(Collectors.toMap(keyExtractor, valueExtractor, BigDecimal::add));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.exception.ServiceException;
|
||||
import com.klp.erp.domain.ErpPurchaseReturn;
|
||||
import com.klp.erp.domain.ErpPurchaseReturnItem;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnItemBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnItemVo;
|
||||
import com.klp.erp.mapper.ErpPurchaseReceiptMapper;
|
||||
import com.klp.erp.mapper.ErpPurchaseReturnItemMapper;
|
||||
import com.klp.erp.mapper.ErpPurchaseReturnMapper;
|
||||
import com.klp.erp.service.IErpPurchaseOrderService;
|
||||
import com.klp.erp.service.IErpPurchaseReturnItemService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ErpPurchaseReturnItemServiceImpl implements IErpPurchaseReturnItemService {
|
||||
|
||||
private final ErpPurchaseReturnItemMapper baseMapper;
|
||||
private final ErpPurchaseReceiptMapper receiptMapper;
|
||||
private final ErpPurchaseReturnMapper returnMapper;
|
||||
private final IErpPurchaseOrderService orderService;
|
||||
|
||||
@Override
|
||||
public ErpPurchaseReturnItemVo queryById(Long returnItemId) {
|
||||
return baseMapper.selectVoById(returnItemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpPurchaseReturnItemVo> queryPageList(ErpPurchaseReturnItemBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturnItem> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpPurchaseReturnItemVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpPurchaseReturnItemVo> queryList(ErpPurchaseReturnItemBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturnItem> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpPurchaseReturnItem> buildQueryWrapper(ErpPurchaseReturnItemBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturnItem> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getReturnId() != null, ErpPurchaseReturnItem::getReturnId, bo.getReturnId());
|
||||
lqw.eq(bo.getItemId() != null, ErpPurchaseReturnItem::getItemId, bo.getItemId());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpPurchaseReturnItemBo bo) {
|
||||
ErpPurchaseReturnItem add = BeanUtil.toBean(bo, ErpPurchaseReturnItem.class);
|
||||
validateReturnQuantity(null, bo);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setReturnItemId(add.getReturnItemId());
|
||||
Long orderId = resolveOrderId(add.getReturnId());
|
||||
if (orderId != null) {
|
||||
orderService.refreshOrderStatus(orderId);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpPurchaseReturnItemBo bo) {
|
||||
ErpPurchaseReturnItem origin = baseMapper.selectById(bo.getReturnItemId());
|
||||
if (origin == null) {
|
||||
return false;
|
||||
}
|
||||
ErpPurchaseReturnItem update = BeanUtil.toBean(bo, ErpPurchaseReturnItem.class);
|
||||
validateReturnQuantity(origin, bo);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
if (flag) {
|
||||
Long orderId = resolveOrderId(update.getReturnId());
|
||||
if (orderId != null) {
|
||||
orderService.refreshOrderStatus(orderId);
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void validateReturnQuantity(ErpPurchaseReturnItem origin, ErpPurchaseReturnItemBo bo) {
|
||||
BigDecimal received = safe(receiptMapper.sumQualifiedQtyByItem(bo.getItemId()));
|
||||
BigDecimal existing = safe(baseMapper.sumAllReturnQtyByItem(bo.getItemId()));
|
||||
BigDecimal originQty = origin == null ? BigDecimal.ZERO : safe(origin.getReturnQty());
|
||||
BigDecimal effective = existing.subtract(originQty).add(safe(bo.getReturnQty()));
|
||||
if (effective.compareTo(received) > 0) {
|
||||
throw new ServiceException("退货数量不能超过已收货数量");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
List<ErpPurchaseReturnItem> items = baseMapper.selectBatchIds(ids);
|
||||
boolean flag = baseMapper.deleteBatchIds(ids) > 0;
|
||||
if (flag && items != null && !items.isEmpty()) {
|
||||
Set<Long> orderIds = new HashSet<>();
|
||||
for (ErpPurchaseReturnItem item : items) {
|
||||
Long orderId = resolveOrderId(item.getReturnId());
|
||||
if (orderId != null) {
|
||||
orderIds.add(orderId);
|
||||
}
|
||||
}
|
||||
orderIds.forEach(orderService::refreshOrderStatus);
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
private Long resolveOrderId(Long returnId) {
|
||||
if (returnId == null) {
|
||||
return null;
|
||||
}
|
||||
ErpPurchaseReturn purchaseReturn = returnMapper.selectById(returnId);
|
||||
return purchaseReturn == null ? null : purchaseReturn.getOrderId();
|
||||
}
|
||||
|
||||
private BigDecimal safe(BigDecimal value) {
|
||||
return value == null ? BigDecimal.ZERO : value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.erp.domain.ErpPurchaseReturn;
|
||||
import com.klp.erp.domain.bo.ErpPurchaseReturnBo;
|
||||
import com.klp.erp.domain.vo.ErpPurchaseReturnVo;
|
||||
import com.klp.erp.mapper.ErpPurchaseReturnMapper;
|
||||
import com.klp.erp.service.IErpPurchaseOrderService;
|
||||
import com.klp.erp.service.IErpPurchaseReturnService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ErpPurchaseReturnServiceImpl implements IErpPurchaseReturnService {
|
||||
|
||||
private final ErpPurchaseReturnMapper baseMapper;
|
||||
private final IErpPurchaseOrderService orderService;
|
||||
|
||||
@Override
|
||||
public ErpPurchaseReturnVo queryById(Long returnId) {
|
||||
return baseMapper.selectVoById(returnId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpPurchaseReturnVo> queryPageList(ErpPurchaseReturnBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturn> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpPurchaseReturnVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpPurchaseReturnVo> queryList(ErpPurchaseReturnBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturn> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpPurchaseReturn> buildQueryWrapper(ErpPurchaseReturnBo bo) {
|
||||
LambdaQueryWrapper<ErpPurchaseReturn> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getOrderId() != null, ErpPurchaseReturn::getOrderId, bo.getOrderId());
|
||||
lqw.eq(bo.getStatus() != null, ErpPurchaseReturn::getStatus, bo.getStatus());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpPurchaseReturnBo bo) {
|
||||
ErpPurchaseReturn add = BeanUtil.toBean(bo, ErpPurchaseReturn.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setReturnId(add.getReturnId());
|
||||
if (Objects.equals(add.getStatus(), 1)) {
|
||||
orderService.refreshOrderStatus(add.getOrderId());
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpPurchaseReturnBo bo) {
|
||||
ErpPurchaseReturn update = BeanUtil.toBean(bo, ErpPurchaseReturn.class);
|
||||
validEntityBeforeSave(update);
|
||||
boolean flag = baseMapper.updateById(update) > 0;
|
||||
if (flag && Objects.equals(update.getStatus(), 1)) {
|
||||
orderService.refreshOrderStatus(update.getOrderId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ErpPurchaseReturn entity) {
|
||||
// TODO: 校验退货状态流转
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 校验是否允许删除
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.erp.domain.ErpSupplierPrice;
|
||||
import com.klp.erp.domain.bo.ErpSupplierPriceBo;
|
||||
import com.klp.erp.domain.bo.MaterialTypeQueryBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierPriceVo;
|
||||
import com.klp.erp.domain.vo.MaterialTypeOptionVo;
|
||||
import com.klp.erp.mapper.ErpSupplierPriceMapper;
|
||||
import com.klp.erp.service.IErpSupplierPriceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ErpSupplierPriceServiceImpl implements IErpSupplierPriceService {
|
||||
|
||||
private final ErpSupplierPriceMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public ErpSupplierPriceVo queryById(Long priceId) {
|
||||
return baseMapper.selectVoById(priceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpSupplierPriceVo> queryPageList(ErpSupplierPriceBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpSupplierPrice> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpSupplierPriceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpSupplierPriceVo> queryList(ErpSupplierPriceBo bo) {
|
||||
LambdaQueryWrapper<ErpSupplierPrice> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpSupplierPrice> buildQueryWrapper(ErpSupplierPriceBo bo) {
|
||||
LambdaQueryWrapper<ErpSupplierPrice> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(bo.getSupplierId() != null, ErpSupplierPrice::getSupplierId, bo.getSupplierId());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMaterialTypeCode()), ErpSupplierPrice::getMaterialTypeCode, bo.getMaterialTypeCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getSpecification()), ErpSupplierPrice::getSpecification, bo.getSpecification());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpSupplierPriceBo bo) {
|
||||
ErpSupplierPrice add = BeanUtil.toBean(bo, ErpSupplierPrice.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setPriceId(add.getPriceId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpSupplierPriceBo bo) {
|
||||
ErpSupplierPrice update = BeanUtil.toBean(bo, ErpSupplierPrice.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ErpSupplierPrice entity) {
|
||||
// TODO: 唯一性/有效期校验
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 删除前校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MaterialTypeOptionVo> queryMaterialTypeOptions(MaterialTypeQueryBo bo) {
|
||||
return baseMapper.selectMaterialTypeOptions(bo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package com.klp.erp.service.impl;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.klp.common.core.domain.PageQuery;
|
||||
import com.klp.common.core.page.TableDataInfo;
|
||||
import com.klp.common.utils.StringUtils;
|
||||
import com.klp.erp.domain.ErpSupplier;
|
||||
import com.klp.erp.domain.bo.ErpSupplierBo;
|
||||
import com.klp.erp.domain.vo.ErpSupplierVo;
|
||||
import com.klp.erp.mapper.ErpSupplierMapper;
|
||||
import com.klp.erp.service.IErpSupplierService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class ErpSupplierServiceImpl implements IErpSupplierService {
|
||||
|
||||
private final ErpSupplierMapper baseMapper;
|
||||
|
||||
@Override
|
||||
public ErpSupplierVo queryById(Long supplierId) {
|
||||
return baseMapper.selectVoById(supplierId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableDataInfo<ErpSupplierVo> queryPageList(ErpSupplierBo bo, PageQuery pageQuery) {
|
||||
LambdaQueryWrapper<ErpSupplier> lqw = buildQueryWrapper(bo);
|
||||
Page<ErpSupplierVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ErpSupplierVo> queryList(ErpSupplierBo bo) {
|
||||
LambdaQueryWrapper<ErpSupplier> lqw = buildQueryWrapper(bo);
|
||||
return baseMapper.selectVoList(lqw);
|
||||
}
|
||||
|
||||
private LambdaQueryWrapper<ErpSupplier> buildQueryWrapper(ErpSupplierBo bo) {
|
||||
LambdaQueryWrapper<ErpSupplier> lqw = Wrappers.lambdaQuery();
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getSupplierCode()), ErpSupplier::getSupplierCode, bo.getSupplierCode());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), ErpSupplier::getName, bo.getName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getType()), ErpSupplier::getType, bo.getType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getCreditRating()), ErpSupplier::getCreditRating, bo.getCreditRating());
|
||||
return lqw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean insertByBo(ErpSupplierBo bo) {
|
||||
ErpSupplier add = BeanUtil.toBean(bo, ErpSupplier.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
if (flag) {
|
||||
bo.setSupplierId(add.getSupplierId());
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean updateByBo(ErpSupplierBo bo) {
|
||||
ErpSupplier update = BeanUtil.toBean(bo, ErpSupplier.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
private void validEntityBeforeSave(ErpSupplier entity) {
|
||||
// TODO: 唯一性校验
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
||||
if (isValid) {
|
||||
// TODO: 删除校验
|
||||
}
|
||||
return baseMapper.deleteBatchIds(ids) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpPurchaseOrderItemMapper">
|
||||
|
||||
<resultMap id="ErpPurchaseOrderItemResult" type="com.klp.erp.domain.ErpPurchaseOrderItem">
|
||||
<result property="itemId" column="item_id"/>
|
||||
<result property="orderId" column="order_id"/>
|
||||
<result property="materialTypeCode" column="material_type_code"/>
|
||||
<result property="specification" column="specification"/>
|
||||
<result property="quantity" column="quantity"/>
|
||||
<result property="unitPrice" column="unit_price"/>
|
||||
<result property="amount" column="amount"/>
|
||||
<result property="currentStock" column="current_stock"/>
|
||||
<result property="onTheWay" column="on_the_way"/>
|
||||
<result property="salesDemand" column="sales_demand"/>
|
||||
<result property="suggestPurchase" column="suggest_purchase"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpPurchaseReceiptMapper">
|
||||
|
||||
<resultMap id="ErpPurchaseReceiptResult" type="com.klp.erp.domain.ErpPurchaseReceipt">
|
||||
<result property="receiptId" column="receipt_id"/>
|
||||
<result property="orderId" column="order_id"/>
|
||||
<result property="itemId" column="item_id"/>
|
||||
<result property="receivedQty" column="received_qty"/>
|
||||
<result property="receiptTime" column="receipt_time"/>
|
||||
<result property="qualityResult" column="quality_result"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="sumQualifiedQtyByItem" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(received_qty), 0)
|
||||
FROM erp_purchase_receipt
|
||||
WHERE del_flag = 0
|
||||
AND item_id = #{itemId}
|
||||
AND (
|
||||
quality_result IS NULL
|
||||
OR UPPER(quality_result) IN ('QUALIFIED', '合格', 'PASS')
|
||||
)
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpPurchaseReportMapper">
|
||||
|
||||
<select id="sumTotalAmount" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(total_amount), 0)
|
||||
FROM erp_purchase_order
|
||||
WHERE del_flag = 0
|
||||
<if test="beginTime != null and beginTime != ''">
|
||||
AND create_time >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null and endTime != ''">
|
||||
AND create_time <= #{endTime}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="sumAmountBySupplier" resultType="java.util.HashMap">
|
||||
SELECT supplier_id AS supplierId,
|
||||
COALESCE(SUM(total_amount), 0) AS totalAmount,
|
||||
COUNT(*) AS orderCount
|
||||
FROM erp_purchase_order
|
||||
WHERE del_flag = 0
|
||||
<if test="beginTime != null and beginTime != ''">
|
||||
AND create_time >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null and endTime != ''">
|
||||
AND create_time <= #{endTime}
|
||||
</if>
|
||||
GROUP BY supplier_id
|
||||
ORDER BY totalAmount DESC
|
||||
</select>
|
||||
|
||||
<select id="selectPriceTrend" resultType="java.util.HashMap">
|
||||
SELECT DATE_FORMAT(po.order_date, '%Y-%m') AS period,
|
||||
poi.material_type_code AS materialCode,
|
||||
COALESCE(AVG(poi.unit_price), 0) AS avgPrice
|
||||
FROM erp_purchase_order po
|
||||
JOIN erp_purchase_order_item poi ON po.order_id = poi.order_id
|
||||
WHERE po.del_flag = 0
|
||||
AND poi.del_flag = 0
|
||||
<if test="beginTime != null and beginTime != ''">
|
||||
AND po.order_date >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null and endTime != ''">
|
||||
AND po.order_date <= #{endTime}
|
||||
</if>
|
||||
GROUP BY period, poi.material_type_code
|
||||
ORDER BY period ASC
|
||||
</select>
|
||||
|
||||
<select id="selectSupplierQuality" resultType="java.util.HashMap">
|
||||
SELECT po.supplier_id AS supplierId,
|
||||
COALESCE(SUM(pr.received_qty), 0) AS receivedQty,
|
||||
COALESCE(SUM(CASE WHEN r.status = 1 THEN ri.return_qty ELSE 0 END), 0) AS returnQty,
|
||||
COALESCE(SUM(CASE WHEN r.status = 1 THEN ri.return_qty ELSE 0 END), 0) /
|
||||
NULLIF(COALESCE(SUM(pr.received_qty), 0), 0) AS returnRate
|
||||
FROM erp_purchase_order po
|
||||
LEFT JOIN erp_purchase_receipt pr
|
||||
ON pr.order_id = po.order_id AND pr.del_flag = 0
|
||||
LEFT JOIN erp_purchase_return r
|
||||
ON r.order_id = po.order_id AND r.del_flag = 0
|
||||
LEFT JOIN erp_purchase_return_item ri
|
||||
ON ri.return_id = r.return_id AND ri.del_flag = 0
|
||||
WHERE po.del_flag = 0
|
||||
<if test="beginTime != null and beginTime != ''">
|
||||
AND po.create_time >= #{beginTime}
|
||||
</if>
|
||||
<if test="endTime != null and endTime != ''">
|
||||
AND po.create_time <= #{endTime}
|
||||
</if>
|
||||
GROUP BY po.supplier_id
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpPurchaseReturnItemMapper">
|
||||
|
||||
<resultMap id="ErpPurchaseReturnItemResult" type="com.klp.erp.domain.ErpPurchaseReturnItem">
|
||||
<result property="returnItemId" column="return_item_id"/>
|
||||
<result property="returnId" column="return_id"/>
|
||||
<result property="itemId" column="item_id"/>
|
||||
<result property="returnQty" column="return_qty"/>
|
||||
<result property="photos" column="photos"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="sumAllReturnQtyByItem" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(return_qty), 0)
|
||||
FROM erp_purchase_return_item
|
||||
WHERE del_flag = 0
|
||||
AND item_id = #{itemId}
|
||||
</select>
|
||||
|
||||
<select id="sumCompletedReturnQtyByItem" resultType="java.math.BigDecimal">
|
||||
SELECT COALESCE(SUM(ri.return_qty), 0)
|
||||
FROM erp_purchase_return_item ri
|
||||
JOIN erp_purchase_return r ON ri.return_id = r.return_id
|
||||
WHERE ri.del_flag = 0
|
||||
AND r.del_flag = 0
|
||||
AND r.status = 1
|
||||
AND ri.item_id = #{itemId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpPurchaseReturnMapper">
|
||||
|
||||
<resultMap id="ErpPurchaseReturnResult" type="com.klp.erp.domain.ErpPurchaseReturn">
|
||||
<result property="returnId" column="return_id"/>
|
||||
<result property="orderId" column="order_id"/>
|
||||
<result property="returnType" column="return_type"/>
|
||||
<result property="reason" column="reason"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
|
||||
25
klp-erp/src/main/resources/mapper/erp/ErpSupplierMapper.xml
Normal file
25
klp-erp/src/main/resources/mapper/erp/ErpSupplierMapper.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpSupplierMapper">
|
||||
|
||||
<resultMap id="ErpSupplierResult" type="com.klp.erp.domain.ErpSupplier">
|
||||
<result property="supplierId" column="supplier_id"/>
|
||||
<result property="supplierCode" column="supplier_code"/>
|
||||
<result property="name" column="name"/>
|
||||
<result property="type" column="type"/>
|
||||
<result property="creditRating" column="credit_rating"/>
|
||||
<result property="contactPerson" column="contact_person"/>
|
||||
<result property="contactPhone" column="contact_phone"/>
|
||||
<result property="address" column="address"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.ErpSupplierPriceMapper">
|
||||
|
||||
<resultMap id="ErpSupplierPriceResult" type="com.klp.erp.domain.ErpSupplierPrice">
|
||||
<result property="priceId" column="price_id"/>
|
||||
<result property="supplierId" column="supplier_id"/>
|
||||
<result property="materialTypeCode" column="material_type_code"/>
|
||||
<result property="specification" column="specification"/>
|
||||
<result property="price" column="price"/>
|
||||
<result property="validFrom" column="valid_from"/>
|
||||
<result property="validTo" column="valid_to"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="updateBy" column="update_by"/>
|
||||
<result property="updateTime" column="update_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectMaterialTypeOptions" resultType="com.klp.erp.domain.vo.MaterialTypeOptionVo"
|
||||
parameterType="com.klp.erp.domain.bo.MaterialTypeQueryBo">
|
||||
SELECT DISTINCT
|
||||
esp.material_type_code AS materialTypeCode,
|
||||
esp.specification AS specification,
|
||||
esp.supplier_id AS supplierId,
|
||||
es.name AS supplierName,
|
||||
esp.price AS latestPrice
|
||||
FROM erp_supplier_price esp
|
||||
LEFT JOIN erp_supplier es ON esp.supplier_id = es.supplier_id
|
||||
<where>
|
||||
esp.del_flag = 0
|
||||
<if test="supplierId != null">
|
||||
AND esp.supplier_id = #{supplierId}
|
||||
</if>
|
||||
<if test="materialTypeCode != null and materialTypeCode != ''">
|
||||
AND esp.material_type_code LIKE CONCAT('%', #{materialTypeCode}, '%')
|
||||
</if>
|
||||
<if test="specification != null and specification != ''">
|
||||
AND esp.specification LIKE CONCAT('%', #{specification}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY esp.material_type_code, esp.specification
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.klp.erp.mapper.PurchaseRequirementCalcMapper">
|
||||
|
||||
<resultMap id="ProductDemandMap" type="com.klp.erp.domain.dto.ProductDemandDTO">
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="demandQuantity" column="demand_quantity"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="ProductStockMap" type="com.klp.erp.domain.dto.ProductStockDTO">
|
||||
<result property="productId" column="product_id"/>
|
||||
<result property="coilCount" column="coil_count"/>
|
||||
<result property="totalWeight" column="total_weight"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="RawStockMap" type="com.klp.erp.domain.dto.RawStockDTO">
|
||||
<result property="rawMaterialId" column="raw_material_id"/>
|
||||
<result property="coilCount" column="coil_count"/>
|
||||
<result property="totalWeight" column="total_weight"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="RawTransitMap" type="com.klp.erp.domain.dto.RawTransitDTO">
|
||||
<result property="rawMaterialId" column="raw_material_id"/>
|
||||
<result property="quantity" column="quantity"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectProductDemand" resultMap="ProductDemandMap">
|
||||
SELECT
|
||||
od.product_id,
|
||||
COALESCE(SUM(od.quantity), 0) AS demand_quantity
|
||||
FROM wms_order_detail od
|
||||
JOIN wms_order o ON od.order_id = o.order_id
|
||||
WHERE o.del_flag = 0
|
||||
AND od.del_flag = 0
|
||||
AND o.order_status IN (0, 1)
|
||||
GROUP BY od.product_id
|
||||
</select>
|
||||
|
||||
<select id="selectProductStock" resultMap="ProductStockMap">
|
||||
SELECT
|
||||
item_id AS product_id,
|
||||
COUNT(*) AS coil_count,
|
||||
COALESCE(SUM(net_weight), 0) AS total_weight
|
||||
FROM wms_material_coil
|
||||
WHERE del_flag = 0
|
||||
AND status = 0
|
||||
AND data_type = 0
|
||||
AND item_type = 'product'
|
||||
AND (material_type IS NULL OR material_type <> '废品')
|
||||
GROUP BY item_id
|
||||
</select>
|
||||
|
||||
<select id="selectRawStock" resultMap="RawStockMap">
|
||||
SELECT
|
||||
item_id AS raw_material_id,
|
||||
COUNT(*) AS coil_count,
|
||||
COALESCE(SUM(net_weight), 0) AS total_weight
|
||||
FROM wms_material_coil
|
||||
WHERE del_flag = 0
|
||||
AND status = 0
|
||||
AND data_type = 0
|
||||
AND item_type = 'raw_material'
|
||||
AND (material_type IS NULL OR material_type <> '废品')
|
||||
GROUP BY item_id
|
||||
</select>
|
||||
|
||||
<sql id="PurchaseOrderJoin">
|
||||
FROM erp_purchase_order_item poi
|
||||
JOIN erp_purchase_order po ON poi.order_id = po.order_id
|
||||
LEFT JOIN wms_raw_material rm ON rm.raw_material_code = poi.material_type_code
|
||||
WHERE poi.del_flag = 0
|
||||
AND po.del_flag = 0
|
||||
AND rm.raw_material_id IS NOT NULL
|
||||
</sql>
|
||||
|
||||
<select id="selectRawInTransit" resultMap="RawTransitMap">
|
||||
SELECT
|
||||
rm.raw_material_id,
|
||||
COALESCE(SUM(poi.quantity), 0) AS quantity
|
||||
<include refid="PurchaseOrderJoin"/>
|
||||
AND po.order_status = 1
|
||||
GROUP BY rm.raw_material_id
|
||||
</select>
|
||||
|
||||
<select id="selectRawPending" resultMap="RawTransitMap">
|
||||
SELECT
|
||||
rm.raw_material_id,
|
||||
COALESCE(SUM(poi.quantity), 0) AS quantity
|
||||
<include refid="PurchaseOrderJoin"/>
|
||||
AND po.order_status = 0
|
||||
GROUP BY rm.raw_material_id
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
289
klp-ui/src/api/erp/purchase.js
Normal file
289
klp-ui/src/api/erp/purchase.js
Normal file
@@ -0,0 +1,289 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 供应商
|
||||
export function listSupplier(query) {
|
||||
return request({
|
||||
url: '/erp/supplier/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addSupplier(data) {
|
||||
return request({
|
||||
url: '/erp/supplier',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateSupplier(data) {
|
||||
return request({
|
||||
url: '/erp/supplier',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delSupplier(ids) {
|
||||
return request({
|
||||
url: `/erp/supplier/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 供应商价格
|
||||
export function listSupplierPrice(query) {
|
||||
return request({
|
||||
url: '/erp/supplierPrice/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addSupplierPrice(data) {
|
||||
return request({
|
||||
url: '/erp/supplierPrice',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateSupplierPrice(data) {
|
||||
return request({
|
||||
url: '/erp/supplierPrice',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delSupplierPrice(ids) {
|
||||
return request({
|
||||
url: `/erp/supplierPrice/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 采购订单
|
||||
export function listPurchaseOrder(query) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrder/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseOrder(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrder',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseOrder(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrder',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPurchaseOrder(ids) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrder/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function confirmPurchaseOrder(orderId) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrder/${orderId}/confirm`,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function partialPurchaseOrder(orderId) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrder/${orderId}/partial`,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function completePurchaseOrder(orderId) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrder/${orderId}/complete`,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function cancelPurchaseOrder(orderId) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrder/${orderId}/cancel`,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 采购订单明细
|
||||
export function listPurchaseOrderItem(query) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrderItem/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseOrderItem(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrderItem',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseOrderItem(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseOrderItem',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPurchaseOrderItem(ids) {
|
||||
return request({
|
||||
url: `/erp/purchaseOrderItem/${ids}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 采购需求分析
|
||||
export function analyzePurchaseRequirement(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseRequirement/analyze',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 收货记录
|
||||
export function listPurchaseReceipt(query) {
|
||||
return request({
|
||||
url: '/erp/purchaseReceipt/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseReceipt(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReceipt',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseReceipt(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReceipt',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPurchaseReceipt(receiptId) {
|
||||
return request({
|
||||
url: `/erp/purchaseReceipt/${receiptId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 退货主表
|
||||
export function listPurchaseReturn(query) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturn/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseReturn(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturn',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseReturn(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturn',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPurchaseReturn(returnIds) {
|
||||
return request({
|
||||
url: `/erp/purchaseReturn/${returnIds}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 退货明细
|
||||
export function listPurchaseReturnItem(query) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturnItem/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addPurchaseReturnItem(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturnItem',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePurchaseReturnItem(data) {
|
||||
return request({
|
||||
url: '/erp/purchaseReturnItem',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delPurchaseReturnItem(itemIds) {
|
||||
return request({
|
||||
url: `/erp/purchaseReturnItem/${itemIds}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 报表
|
||||
export function getPurchaseReportSummary(params) {
|
||||
return request({
|
||||
url: '/erp/purchaseReport/summary',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getPurchasePriceTrend(params) {
|
||||
return request({
|
||||
url: '/erp/purchaseReport/trend',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getSupplierQuality(params) {
|
||||
return request({
|
||||
url: '/erp/purchaseReport/supplierQuality',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
394
klp-ui/src/views/erp/order/index.vue
Normal file
394
klp-ui/src/views/erp/order/index.vue
Normal file
@@ -0,0 +1,394 @@
|
||||
<template>
|
||||
<div class="erp-order-page">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>采购订单列表</span>
|
||||
<div>
|
||||
<el-button type="primary" size="mini" @click="openOrderDialog()">新增订单</el-button>
|
||||
<el-button size="mini" @click="openItemDialog()">维护明细</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="orderQuery.orderCode" placeholder="订单编号" size="small" clearable class="toolbar-input" />
|
||||
<el-input v-model="orderQuery.supplierId" placeholder="供应商ID" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="orderQuery.orderStatus" placeholder="状态" size="small" clearable class="toolbar-input">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="执行中" :value="1" />
|
||||
<el-option label="部分到货" :value="2" />
|
||||
<el-option label="已完成" :value="3" />
|
||||
<el-option label="已取消" :value="4" />
|
||||
</el-select>
|
||||
<el-date-picker
|
||||
v-model="orderRange"
|
||||
type="daterange"
|
||||
unlink-panels
|
||||
value-format="yyyy-MM-dd"
|
||||
start-placeholder="下单开始"
|
||||
end-placeholder="下单结束"
|
||||
size="small"
|
||||
/>
|
||||
<el-button size="small" type="primary" @click="loadOrders">查询</el-button>
|
||||
<el-button size="small" @click="resetOrderQuery">重置</el-button>
|
||||
</div>
|
||||
<el-table :data="orderList" border stripe highlight-current-row size="small" v-loading="orderLoading">
|
||||
<el-table-column prop="orderCode" label="订单编号" width="150" fixed="left" />
|
||||
<el-table-column prop="supplierId" label="供应商ID" width="120" />
|
||||
<el-table-column prop="orderDate" label="下单日期" width="120" />
|
||||
<el-table-column prop="expectedArrival" label="期望到货" width="120" />
|
||||
<el-table-column prop="orderType" label="类型" width="120" />
|
||||
<el-table-column prop="totalAmount" label="金额" width="120" />
|
||||
<el-table-column label="状态" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="statusTag(scope.row.orderStatus)" size="mini">{{ statusText(scope.row.orderStatus) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="360" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openOrderDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteOrder(scope.row)" style="color:#c0392b">删除</el-button>
|
||||
<el-divider direction="vertical" />
|
||||
<el-button type="text" size="mini" @click="confirmOrder(scope.row)">下达</el-button>
|
||||
<el-button type="text" size="mini" @click="partialOrder(scope.row)">部分到货</el-button>
|
||||
<el-button type="text" size="mini" @click="completeOrder(scope.row)">完成</el-button>
|
||||
<el-button type="text" size="mini" @click="cancelOrder(scope.row)">取消</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="orderTotal > 0"
|
||||
:total="orderTotal"
|
||||
:page.sync="orderQuery.pageNum"
|
||||
:limit.sync="orderQuery.pageSize"
|
||||
@pagination="loadOrders"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<!-- 订单弹窗 -->
|
||||
<el-dialog :title="orderDialog.title" :visible.sync="orderDialog.visible" width="600px">
|
||||
<el-form :model="orderDialog.form" :rules="orderRules" ref="orderForm" label-width="100px" size="small">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="订单编号" prop="orderCode">
|
||||
<el-input v-model="orderDialog.form.orderCode" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="供应商ID" prop="supplierId">
|
||||
<el-input v-model="orderDialog.form.supplierId" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="下单日期" prop="orderDate">
|
||||
<el-date-picker v-model="orderDialog.form.orderDate" type="date" value-format="yyyy-MM-dd" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="期望到货">
|
||||
<el-date-picker v-model="orderDialog.form.expectedArrival" type="date" value-format="yyyy-MM-dd" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-form-item label="订单类型">
|
||||
<el-input v-model="orderDialog.form.orderType" />
|
||||
</el-form-item>
|
||||
<el-form-item label="金额">
|
||||
<el-input-number v-model="orderDialog.form.totalAmount" :min="0" :precision="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="orderDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="orderDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitOrder">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 明细弹窗 -->
|
||||
<el-dialog :title="itemDialog.title" :visible.sync="itemDialog.visible" width="640px">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="itemQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-button size="small" type="primary" @click="loadItems">查询</el-button>
|
||||
<el-button size="small" @click="resetItemQuery">重置</el-button>
|
||||
<div class="toolbar-spacer"></div>
|
||||
<el-button type="primary" size="small" @click="openItemForm()">新增明细</el-button>
|
||||
</div>
|
||||
<el-table :data="itemList" border size="small" v-loading="itemLoading">
|
||||
<el-table-column prop="orderId" label="订单ID" width="120" />
|
||||
<el-table-column prop="materialTypeCode" label="物料类型" width="150" />
|
||||
<el-table-column prop="specification" label="规格" min-width="150" />
|
||||
<el-table-column prop="quantity" label="数量" width="100" />
|
||||
<el-table-column prop="unitPrice" label="单价" width="100" />
|
||||
<el-table-column label="操作" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openItemForm(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteItem(scope.row)" style="color:#c0392b">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="itemTotal > 0"
|
||||
:total="itemTotal"
|
||||
:page.sync="itemQuery.pageNum"
|
||||
:limit.sync="itemQuery.pageSize"
|
||||
@pagination="loadItems"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 明细编辑 -->
|
||||
<el-dialog :title="itemFormDialog.title" :visible.sync="itemFormDialog.visible" width="520px">
|
||||
<el-form :model="itemFormDialog.form" :rules="itemRules" ref="itemForm" label-width="110px" size="small">
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input v-model="itemFormDialog.form.orderId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="物料类型" prop="materialTypeCode">
|
||||
<el-input v-model="itemFormDialog.form.materialTypeCode" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格">
|
||||
<el-input v-model="itemFormDialog.form.specification" />
|
||||
</el-form-item>
|
||||
<el-form-item label="采购数量" prop="quantity">
|
||||
<el-input-number v-model="itemFormDialog.form.quantity" :min="0" :precision="3" />
|
||||
</el-form-item>
|
||||
<el-form-item label="含税单价">
|
||||
<el-input-number v-model="itemFormDialog.form.unitPrice" :min="0" :precision="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="itemFormDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="itemFormDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitItem">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listPurchaseOrder,
|
||||
addPurchaseOrder,
|
||||
updatePurchaseOrder,
|
||||
delPurchaseOrder,
|
||||
confirmPurchaseOrder,
|
||||
partialPurchaseOrder,
|
||||
completePurchaseOrder,
|
||||
cancelPurchaseOrder,
|
||||
listPurchaseOrderItem,
|
||||
addPurchaseOrderItem,
|
||||
updatePurchaseOrderItem,
|
||||
delPurchaseOrderItem
|
||||
} from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseOrder',
|
||||
data() {
|
||||
return {
|
||||
orderQuery: { pageNum: 1, pageSize: 10, orderCode: null, supplierId: null, orderStatus: null },
|
||||
orderRange: [],
|
||||
orderList: [],
|
||||
orderTotal: 0,
|
||||
orderLoading: false,
|
||||
orderDialog: { visible: false, title: '', form: {} },
|
||||
orderRules: {
|
||||
orderCode: [{ required: true, message: '请输入订单编号', trigger: 'blur' }],
|
||||
supplierId: [{ required: true, message: '请输入供应商ID', trigger: 'blur' }]
|
||||
},
|
||||
itemDialog: { visible: false, title: '订单明细' },
|
||||
itemQuery: { pageNum: 1, pageSize: 10, orderId: null },
|
||||
itemList: [],
|
||||
itemTotal: 0,
|
||||
itemLoading: false,
|
||||
itemFormDialog: { visible: false, title: '', form: {} },
|
||||
itemRules: {
|
||||
orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
|
||||
materialTypeCode: [{ required: true, message: '请输入物料类型', trigger: 'blur' }],
|
||||
quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadOrders()
|
||||
},
|
||||
methods: {
|
||||
loadOrders() {
|
||||
const query = { ...this.orderQuery }
|
||||
if (this.orderRange && this.orderRange.length === 2) {
|
||||
query.beginTime = this.orderRange[0]
|
||||
query.endTime = this.orderRange[1]
|
||||
}
|
||||
this.orderLoading = true
|
||||
listPurchaseOrder(query)
|
||||
.then(res => {
|
||||
this.orderList = res.rows || []
|
||||
this.orderTotal = res.total || 0
|
||||
})
|
||||
.finally(() => {
|
||||
this.orderLoading = false
|
||||
})
|
||||
},
|
||||
resetOrderQuery() {
|
||||
this.orderQuery = { pageNum: 1, pageSize: 10, orderCode: null, supplierId: null, orderStatus: null }
|
||||
this.orderRange = []
|
||||
this.loadOrders()
|
||||
},
|
||||
openOrderDialog(row) {
|
||||
if (row) {
|
||||
this.orderDialog.form = { ...row }
|
||||
this.orderDialog.title = '编辑采购订单'
|
||||
} else {
|
||||
this.orderDialog.form = { orderCode: '', supplierId: '', orderDate: '', orderStatus: 0 }
|
||||
this.orderDialog.title = '新增采购订单'
|
||||
}
|
||||
this.orderDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.orderForm && this.$refs.orderForm.clearValidate())
|
||||
},
|
||||
submitOrder() {
|
||||
this.$refs.orderForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.orderDialog.form.orderId ? updatePurchaseOrder : addPurchaseOrder
|
||||
api(this.orderDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.orderDialog.visible = false
|
||||
this.loadOrders()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteOrder(row) {
|
||||
this.$confirm('确定删除该订单吗?', '提示').then(() => {
|
||||
return delPurchaseOrder(row.orderId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadOrders()
|
||||
})
|
||||
},
|
||||
confirmOrder(row) {
|
||||
confirmPurchaseOrder(row.orderId).then(() => {
|
||||
this.$message.success('已下达')
|
||||
this.loadOrders()
|
||||
})
|
||||
},
|
||||
partialOrder(row) {
|
||||
partialPurchaseOrder(row.orderId).then(() => {
|
||||
this.$message.success('已标记部分到货')
|
||||
this.loadOrders()
|
||||
})
|
||||
},
|
||||
completeOrder(row) {
|
||||
completePurchaseOrder(row.orderId).then(() => {
|
||||
this.$message.success('订单已完成')
|
||||
this.loadOrders()
|
||||
})
|
||||
},
|
||||
cancelOrder(row) {
|
||||
cancelPurchaseOrder(row.orderId).then(() => {
|
||||
this.$message.success('订单已取消')
|
||||
this.loadOrders()
|
||||
})
|
||||
},
|
||||
statusText(status) {
|
||||
switch (status) {
|
||||
case 0: return '草稿'
|
||||
case 1: return '执行中'
|
||||
case 2: return '部分到货'
|
||||
case 3: return '已完成'
|
||||
case 4: return '已取消'
|
||||
default: return '-'
|
||||
}
|
||||
},
|
||||
statusTag(status) {
|
||||
const map = {
|
||||
0: 'info',
|
||||
1: 'primary',
|
||||
2: 'warning',
|
||||
3: 'success',
|
||||
4: 'danger'
|
||||
}
|
||||
return map[status] || 'info'
|
||||
},
|
||||
openItemDialog() {
|
||||
this.itemDialog.visible = true
|
||||
this.loadItems()
|
||||
},
|
||||
loadItems() {
|
||||
this.itemLoading = true
|
||||
listPurchaseOrderItem(this.itemQuery)
|
||||
.then(res => {
|
||||
this.itemList = res.rows || []
|
||||
this.itemTotal = res.total || 0
|
||||
})
|
||||
.finally(() => {
|
||||
this.itemLoading = false
|
||||
})
|
||||
},
|
||||
resetItemQuery() {
|
||||
this.itemQuery = { pageNum: 1, pageSize: 10, orderId: null }
|
||||
this.loadItems()
|
||||
},
|
||||
openItemForm(row) {
|
||||
if (row) {
|
||||
this.itemFormDialog.form = { ...row }
|
||||
this.itemFormDialog.title = '编辑明细'
|
||||
} else {
|
||||
this.itemFormDialog.form = { orderId: '', materialTypeCode: '', quantity: 0 }
|
||||
this.itemFormDialog.title = '新增明细'
|
||||
}
|
||||
this.itemFormDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.itemForm && this.$refs.itemForm.clearValidate())
|
||||
},
|
||||
submitItem() {
|
||||
this.$refs.itemForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.itemFormDialog.form.itemId ? updatePurchaseOrderItem : addPurchaseOrderItem
|
||||
api(this.itemFormDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.itemFormDialog.visible = false
|
||||
this.loadItems()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteItem(row) {
|
||||
this.$confirm('确定删除该明细吗?', '提示').then(() => {
|
||||
return delPurchaseOrderItem(row.itemId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadItems()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-order-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
border: 1px solid #d0d5d8;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
flex-wrap: wrap;
|
||||
.toolbar-input {
|
||||
width: 150px;
|
||||
margin-right: 8px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
}
|
||||
.toolbar-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
734
klp-ui/src/views/erp/purchase/index.vue
Normal file
734
klp-ui/src/views/erp/purchase/index.vue
Normal file
@@ -0,0 +1,734 @@
|
||||
<template>
|
||||
<div class="erp-purchase-page">
|
||||
<el-row :gutter="16" class="summary-row">
|
||||
<el-col :span="6">
|
||||
<div class="summary-card">
|
||||
<p class="label">采购总金额</p>
|
||||
<p class="value">¥{{ summary.totalAmount | formatAmount }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="summary-card">
|
||||
<p class="label">计划采购量</p>
|
||||
<p class="value">{{ summary.suggestionTotal }} 吨</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="summary-card">
|
||||
<p class="label">待处理订单</p>
|
||||
<p class="value">{{ summary.pendingOrder }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="summary-card">
|
||||
<p class="label">供应商数量</p>
|
||||
<p class="value">{{ summary.supplierBrief.length }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-card class="panel-card" shadow="never">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>采购需求分析</span>
|
||||
<div class="panel-actions">
|
||||
<el-switch v-model="persistResult" active-text="写入建议表" inactive-text="仅计算" />
|
||||
<el-button type="primary" size="mini" @click="handleAnalyze" :loading="analysisLoading">执行分析</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="mappingRows" border size="small" class="mapping-table">
|
||||
<el-table-column label="产品ID" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.productId" placeholder="产品ID" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原料ID" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.rawMaterialId" placeholder="原料ID" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="转换率" width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number v-model="scope.row.conversionRate" :min="0" :max="1" :step="0.01" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="removeMappingRow(scope.$index)" :disabled="mappingRows.length === 1">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="mapping-toolbar">
|
||||
<el-button icon="el-icon-plus" size="mini" @click="addMappingRow">新增映射</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="analysisData"
|
||||
v-loading="analysisLoading"
|
||||
size="small"
|
||||
border
|
||||
class="analysis-table"
|
||||
show-summary
|
||||
:summary-method="analysisSummary"
|
||||
>
|
||||
<el-table-column label="产品" prop="productName" min-width="180">
|
||||
<template slot-scope="scope">
|
||||
<div class="cell-title">{{ scope.row.productName || '-' }}</div>
|
||||
<div class="cell-sub">ID: {{ scope.row.productId || '-' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" prop="specification" min-width="140" />
|
||||
<el-table-column label="销售需求(吨)" prop="salesDemand" min-width="120" />
|
||||
<el-table-column label="成品库存/卷" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.productStockWeight }}</div>
|
||||
<div class="cell-sub">{{ scope.row.productStockCoilCount }} 卷</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原料折算(吨)" prop="rawStockConverted" min-width="120" />
|
||||
<el-table-column label="在途折算(吨)" prop="inTransitConverted" min-width="120" />
|
||||
<el-table-column label="待下达折算(吨)" prop="pendingConverted" min-width="120" />
|
||||
<el-table-column label="建议采购(吨)" prop="suggestedPurchase" min-width="120" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card class="panel-card" shadow="never">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>执行控制</span>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<el-tab-pane label="收货记录" name="receipt">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="receiptQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-input v-model="receiptQuery.itemId" placeholder="明细ID" size="small" clearable class="toolbar-input" />
|
||||
<el-button size="small" type="primary" @click="loadReceipts">查询</el-button>
|
||||
<el-button size="small" @click="resetReceiptQuery">重置</el-button>
|
||||
<div class="toolbar-spacer"></div>
|
||||
<el-button type="primary" size="small" @click="openReceiptDialog()">新增收货</el-button>
|
||||
</div>
|
||||
<el-table :data="receiptList" v-loading="receiptLoading" border size="small">
|
||||
<el-table-column prop="receiptId" label="ID" width="80" />
|
||||
<el-table-column prop="orderId" label="订单ID" width="100" />
|
||||
<el-table-column prop="itemId" label="明细ID" width="100" />
|
||||
<el-table-column prop="receivedQty" label="收货数量" width="100" />
|
||||
<el-table-column prop="qualityResult" label="质检结果" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.qualityResult === 'NG' ? 'danger' : 'success'" size="mini">
|
||||
{{ scope.row.qualityResult || '合格' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="receiptTime" label="收货时间" width="160" />
|
||||
<el-table-column label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openReceiptDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteReceipt(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="receiptTotal > 0"
|
||||
:total="receiptTotal"
|
||||
:page.sync="receiptQuery.pageNum"
|
||||
:limit.sync="receiptQuery.pageSize"
|
||||
@pagination="loadReceipts"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="退货管理" name="return">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable class="toolbar-input">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="完成" :value="1" />
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
|
||||
<el-button size="small" @click="resetReturnQuery">重置</el-button>
|
||||
<div class="toolbar-spacer"></div>
|
||||
<el-button type="primary" size="small" @click="openReturnDialog()">新增退货</el-button>
|
||||
<el-button size="small" @click="openReturnItemDialog()">退货明细</el-button>
|
||||
</div>
|
||||
<el-table :data="returnList" v-loading="returnLoading" border size="small">
|
||||
<el-table-column prop="returnId" label="退货单ID" width="120" />
|
||||
<el-table-column prop="orderId" label="订单ID" width="120" />
|
||||
<el-table-column prop="returnType" label="类型" width="120" />
|
||||
<el-table-column prop="reason" label="原因" min-width="150" />
|
||||
<el-table-column prop="status" label="状态" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="mini">
|
||||
{{ scope.row.status === 1 ? '完成' : '草稿' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openReturnDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteReturn(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="returnTotal > 0"
|
||||
:total="returnTotal"
|
||||
:page.sync="returnQuery.pageNum"
|
||||
:limit.sync="returnQuery.pageSize"
|
||||
@pagination="loadReturns"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
|
||||
<el-card class="panel-card" shadow="never">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>采购报表</span>
|
||||
<div class="panel-actions">
|
||||
<el-date-picker
|
||||
v-model="reportRange"
|
||||
type="monthrange"
|
||||
unlink-panels
|
||||
value-format="yyyy-MM"
|
||||
range-separator="至"
|
||||
start-placeholder="开始月份"
|
||||
end-placeholder="结束月份"
|
||||
@change="loadReports"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<div class="report-block">
|
||||
<h4>供应商采购额TOP</h4>
|
||||
<el-table :data="summary.supplierBrief" size="mini" height="220" border>
|
||||
<el-table-column prop="supplierId" label="供应商ID" width="120" />
|
||||
<el-table-column prop="totalAmount" label="金额" />
|
||||
<el-table-column prop="orderCount" label="订单" width="80" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="report-block">
|
||||
<h4>价格趋势</h4>
|
||||
<el-table :data="priceTrend" size="mini" height="220" border>
|
||||
<el-table-column prop="period" label="月份" width="120" />
|
||||
<el-table-column prop="materialCode" label="物料编码" width="150" />
|
||||
<el-table-column prop="avgPrice" label="平均含税单价" />
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="report-block">
|
||||
<h4>供应商退货率</h4>
|
||||
<el-table :data="supplierQuality" size="mini" height="220" border>
|
||||
<el-table-column prop="supplierId" label="供应商ID" width="120" />
|
||||
<el-table-column prop="receivedQty" label="收货量" />
|
||||
<el-table-column prop="returnQty" label="退货量" />
|
||||
<el-table-column label="退货率">
|
||||
<template slot-scope="scope">
|
||||
{{ formatPercent(scope.row.returnRate) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 收货弹窗 -->
|
||||
<el-dialog :title="receiptDialog.title" :visible.sync="receiptDialog.visible" width="480px">
|
||||
<el-form :model="receiptDialog.form" :rules="receiptRules" ref="receiptForm" label-width="100px" size="small">
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input v-model="receiptDialog.form.orderId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="明细ID" prop="itemId">
|
||||
<el-input v-model="receiptDialog.form.itemId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收货数量" prop="receivedQty">
|
||||
<el-input-number v-model="receiptDialog.form.receivedQty" :min="0" :precision="3" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质检结果" prop="qualityResult">
|
||||
<el-select v-model="receiptDialog.form.qualityResult" clearable placeholder="默认合格">
|
||||
<el-option label="合格" value="OK" />
|
||||
<el-option label="不合格" value="NG" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收货时间">
|
||||
<el-date-picker
|
||||
v-model="receiptDialog.form.receiptTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="自动取当前"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="receiptDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="receiptDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitReceipt">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 退货弹窗 -->
|
||||
<el-dialog :title="returnDialog.title" :visible.sync="returnDialog.visible" width="500px">
|
||||
<el-form :model="returnDialog.form" :rules="returnRules" ref="returnForm" label-width="100px" size="small">
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input v-model="returnDialog.form.orderId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退货类型">
|
||||
<el-select v-model="returnDialog.form.returnType" clearable>
|
||||
<el-option label="质量问题" value="QUALITY" />
|
||||
<el-option label="数量错误" value="QTY" />
|
||||
<el-option label="规格不符" value="SPEC" />
|
||||
<el-option label="其他" value="OTHER" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="退货原因">
|
||||
<el-input type="textarea" v-model="returnDialog.form.reason" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="returnDialog.form.status">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="完成" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="returnDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="returnDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitReturn">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 退货明细弹窗 -->
|
||||
<el-dialog :title="returnItemDialog.title" :visible.sync="returnItemDialog.visible" width="520px">
|
||||
<div class="toolbar">
|
||||
<el-input v-model="returnItemQuery.returnId" placeholder="退货单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-input v-model="returnItemQuery.itemId" placeholder="订单明细ID" size="small" clearable class="toolbar-input" />
|
||||
<el-button size="small" type="primary" @click="loadReturnItems">查询</el-button>
|
||||
<el-button size="small" @click="resetReturnItemQuery">重置</el-button>
|
||||
<div class="toolbar-spacer"></div>
|
||||
<el-button type="primary" size="small" @click="openReturnItemForm()">新增明细</el-button>
|
||||
</div>
|
||||
<el-table :data="returnItemList" v-loading="returnItemLoading" border size="small">
|
||||
<el-table-column prop="returnItemId" label="ID" width="80" />
|
||||
<el-table-column prop="returnId" label="退货单ID" width="100" />
|
||||
<el-table-column prop="itemId" label="订单明细ID" width="120" />
|
||||
<el-table-column prop="returnQty" label="退货数量" width="120" />
|
||||
<el-table-column label="操作" width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openReturnItemForm(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteReturnItem(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="returnItemTotal > 0"
|
||||
:total="returnItemTotal"
|
||||
:page.sync="returnItemQuery.pageNum"
|
||||
:limit.sync="returnItemQuery.pageSize"
|
||||
@pagination="loadReturnItems"
|
||||
/>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 退货明细编辑 -->
|
||||
<el-dialog :title="returnItemFormDialog.title" :visible.sync="returnItemFormDialog.visible" width="420px">
|
||||
<el-form ref="returnItemForm" :model="returnItemFormDialog.form" :rules="returnItemRules" label-width="110px" size="small">
|
||||
<el-form-item label="退货单ID" prop="returnId">
|
||||
<el-input v-model="returnItemFormDialog.form.returnId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单明细ID" prop="itemId">
|
||||
<el-input v-model="returnItemFormDialog.form.itemId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退货数量" prop="returnQty">
|
||||
<el-input-number v-model="returnItemFormDialog.form.returnQty" :min="0" :precision="3" />
|
||||
</el-form-item>
|
||||
<el-form-item label="照片">
|
||||
<el-input v-model="returnItemFormDialog.form.photos" placeholder="图片URL,用逗号分隔" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="returnItemFormDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="returnItemFormDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitReturnItem">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
analyzePurchaseRequirement,
|
||||
listPurchaseReceipt,
|
||||
addPurchaseReceipt,
|
||||
updatePurchaseReceipt,
|
||||
delPurchaseReceipt,
|
||||
listPurchaseReturn,
|
||||
addPurchaseReturn,
|
||||
updatePurchaseReturn,
|
||||
delPurchaseReturn,
|
||||
listPurchaseReturnItem,
|
||||
addPurchaseReturnItem,
|
||||
updatePurchaseReturnItem,
|
||||
delPurchaseReturnItem,
|
||||
getPurchaseReportSummary,
|
||||
getPurchasePriceTrend,
|
||||
getSupplierQuality
|
||||
} from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseWorkbench',
|
||||
data() {
|
||||
return {
|
||||
mappingRows: [{ productId: '', rawMaterialId: '', conversionRate: 1 }],
|
||||
persistResult: false,
|
||||
analysisLoading: false,
|
||||
analysisData: [],
|
||||
summary: { totalAmount: 0, suggestionTotal: 0, pendingOrder: 0, supplierBrief: [] },
|
||||
reportRange: [],
|
||||
priceTrend: [],
|
||||
supplierQuality: [],
|
||||
activeTab: 'receipt',
|
||||
receiptList: [],
|
||||
receiptTotal: 0,
|
||||
receiptLoading: false,
|
||||
receiptQuery: { pageNum: 1, pageSize: 10, orderId: null, itemId: null },
|
||||
receiptDialog: { visible: false, title: '', form: {} },
|
||||
receiptRules: {
|
||||
orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
|
||||
itemId: [{ required: true, message: '请输入明细ID', trigger: 'blur' }],
|
||||
receivedQty: [{ required: true, message: '请输入收货数量', trigger: 'blur' }]
|
||||
},
|
||||
returnList: [],
|
||||
returnTotal: 0,
|
||||
returnLoading: false,
|
||||
returnQuery: { pageNum: 1, pageSize: 10, orderId: null, status: null },
|
||||
returnDialog: { visible: false, title: '', form: {} },
|
||||
returnRules: {
|
||||
orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }]
|
||||
},
|
||||
returnItemDialog: { visible: false, title: '退货明细列表' },
|
||||
returnItemQuery: { pageNum: 1, pageSize: 10, returnId: null, itemId: null },
|
||||
returnItemList: [],
|
||||
returnItemTotal: 0,
|
||||
returnItemLoading: false,
|
||||
returnItemFormDialog: { visible: false, title: '', form: {} },
|
||||
returnItemRules: {
|
||||
returnId: [{ required: true, message: '请输入退货单ID', trigger: 'blur' }],
|
||||
itemId: [{ required: true, message: '请输入订单明细ID', trigger: 'blur' }],
|
||||
returnQty: [{ required: true, message: '请输入退货数量', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatAmount(val) {
|
||||
if (!val) return '0.00'
|
||||
return Number(val).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadReports()
|
||||
this.loadReceipts()
|
||||
this.loadReturns()
|
||||
},
|
||||
methods: {
|
||||
addMappingRow() {
|
||||
this.mappingRows.push({ productId: '', rawMaterialId: '', conversionRate: 1 })
|
||||
},
|
||||
removeMappingRow(index) {
|
||||
if (this.mappingRows.length === 1) return
|
||||
this.mappingRows.splice(index, 1)
|
||||
},
|
||||
handleAnalyze() {
|
||||
if (!this.mappingRows.every(row => row.productId && row.rawMaterialId)) {
|
||||
this.$message.warning('请补全产品与原料映射')
|
||||
return
|
||||
}
|
||||
this.analysisLoading = true
|
||||
const payload = {
|
||||
mappings: this.mappingRows.map(row => ({
|
||||
productId: Number(row.productId),
|
||||
rawMaterialId: Number(row.rawMaterialId),
|
||||
conversionRate: Number(row.conversionRate || 0)
|
||||
})),
|
||||
persistResult: this.persistResult
|
||||
}
|
||||
analyzePurchaseRequirement(payload)
|
||||
.then(res => {
|
||||
this.analysisData = res || []
|
||||
this.summary.suggestionTotal = this.analysisData.reduce((sum, item) => sum + Number(item.suggestedPurchase || 0), 0)
|
||||
this.$message.success('分析完成')
|
||||
})
|
||||
.finally(() => {
|
||||
this.analysisLoading = false
|
||||
})
|
||||
},
|
||||
analysisSummary({ data }) {
|
||||
const sums = []
|
||||
const columns = ['salesDemand', 'productStockWeight', 'rawStockConverted', 'inTransitConverted', 'pendingConverted', 'suggestedPurchase']
|
||||
sums[0] = '总计'
|
||||
data.forEach(row => {
|
||||
columns.forEach((col, idx) => {
|
||||
const value = Number(row[col] || 0)
|
||||
sums[idx + 2] = (Number(sums[idx + 2]) || 0) + value
|
||||
})
|
||||
})
|
||||
return sums
|
||||
},
|
||||
loadReports() {
|
||||
const params = {}
|
||||
if (this.reportRange && this.reportRange.length === 2) {
|
||||
params.beginTime = `${this.reportRange[0]}-01`
|
||||
params.endTime = `${this.reportRange[1]}-31`
|
||||
}
|
||||
getPurchaseReportSummary(params).then(res => {
|
||||
this.summary.totalAmount = res.totalAmount || 0
|
||||
this.summary.supplierBrief = res.bySupplier || []
|
||||
this.summary.pendingOrder = this.summary.supplierBrief.reduce((sum, item) => sum + (item.orderCount || 0), 0)
|
||||
})
|
||||
getPurchasePriceTrend(params).then(res => {
|
||||
this.priceTrend = res || []
|
||||
})
|
||||
getSupplierQuality(params).then(res => {
|
||||
this.supplierQuality = res || []
|
||||
})
|
||||
},
|
||||
formatPercent(value) {
|
||||
if (!value || !isFinite(value)) return '0%'
|
||||
return `${(Number(value) * 100).toFixed(2)}%`
|
||||
},
|
||||
// 收货
|
||||
loadReceipts() {
|
||||
this.receiptLoading = true
|
||||
listPurchaseReceipt(this.receiptQuery)
|
||||
.then(res => {
|
||||
this.receiptList = res.rows || []
|
||||
this.receiptTotal = res.total || 0
|
||||
})
|
||||
.finally(() => {
|
||||
this.receiptLoading = false
|
||||
})
|
||||
},
|
||||
resetReceiptQuery() {
|
||||
this.receiptQuery = { pageNum: 1, pageSize: 10, orderId: null, itemId: null }
|
||||
this.loadReceipts()
|
||||
},
|
||||
openReceiptDialog(row) {
|
||||
if (row) {
|
||||
this.receiptDialog.form = { ...row }
|
||||
this.receiptDialog.title = '编辑收货'
|
||||
} else {
|
||||
this.receiptDialog.form = { orderId: '', itemId: '', receivedQty: 0, qualityResult: 'OK' }
|
||||
this.receiptDialog.title = '新增收货'
|
||||
}
|
||||
this.receiptDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.receiptForm && this.$refs.receiptForm.clearValidate())
|
||||
},
|
||||
submitReceipt() {
|
||||
this.$refs.receiptForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.receiptDialog.form.receiptId ? updatePurchaseReceipt : addPurchaseReceipt
|
||||
api(this.receiptDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.receiptDialog.visible = false
|
||||
this.loadReceipts()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteReceipt(row) {
|
||||
this.$confirm('确定删除该收货记录吗?', '提示').then(() => {
|
||||
return delPurchaseReceipt(row.receiptId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadReceipts()
|
||||
})
|
||||
},
|
||||
// 退货
|
||||
loadReturns() {
|
||||
this.returnLoading = true
|
||||
listPurchaseReturn(this.returnQuery)
|
||||
.then(res => {
|
||||
this.returnList = res.rows || []
|
||||
this.returnTotal = res.total || 0
|
||||
})
|
||||
.finally(() => {
|
||||
this.returnLoading = false
|
||||
})
|
||||
},
|
||||
resetReturnQuery() {
|
||||
this.returnQuery = { pageNum: 1, pageSize: 10, orderId: null, status: null }
|
||||
this.loadReturns()
|
||||
},
|
||||
openReturnDialog(row) {
|
||||
if (row) {
|
||||
this.returnDialog.form = { ...row }
|
||||
this.returnDialog.title = '编辑退货单'
|
||||
} else {
|
||||
this.returnDialog.form = { orderId: '', returnType: 'QUALITY', status: 0 }
|
||||
this.returnDialog.title = '新增退货单'
|
||||
}
|
||||
this.returnDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.returnForm && this.$refs.returnForm.clearValidate())
|
||||
},
|
||||
submitReturn() {
|
||||
this.$refs.returnForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.returnDialog.form.returnId ? updatePurchaseReturn : addPurchaseReturn
|
||||
api(this.returnDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.returnDialog.visible = false
|
||||
this.loadReturns()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteReturn(row) {
|
||||
this.$confirm('确定删除该退货单吗?', '提示').then(() => {
|
||||
return delPurchaseReturn(row.returnId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadReturns()
|
||||
})
|
||||
},
|
||||
// 退货明细
|
||||
openReturnItemDialog() {
|
||||
this.returnItemDialog.visible = true
|
||||
this.loadReturnItems()
|
||||
},
|
||||
loadReturnItems() {
|
||||
this.returnItemLoading = true
|
||||
listPurchaseReturnItem(this.returnItemQuery)
|
||||
.then(res => {
|
||||
this.returnItemList = res.rows || []
|
||||
this.returnItemTotal = res.total || 0
|
||||
})
|
||||
.finally(() => {
|
||||
this.returnItemLoading = false
|
||||
})
|
||||
},
|
||||
resetReturnItemQuery() {
|
||||
this.returnItemQuery = { pageNum: 1, pageSize: 10, returnId: null, itemId: null }
|
||||
this.loadReturnItems()
|
||||
},
|
||||
openReturnItemForm(row) {
|
||||
if (row) {
|
||||
this.returnItemFormDialog.form = { ...row }
|
||||
this.returnItemFormDialog.title = '编辑退货明细'
|
||||
} else {
|
||||
this.returnItemFormDialog.form = { returnId: '', itemId: '', returnQty: 0 }
|
||||
this.returnItemFormDialog.title = '新增退货明细'
|
||||
}
|
||||
this.returnItemFormDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.returnItemForm && this.$refs.returnItemForm.clearValidate())
|
||||
},
|
||||
submitReturnItem() {
|
||||
this.$refs.returnItemForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.returnItemFormDialog.form.returnItemId ? updatePurchaseReturnItem : addPurchaseReturnItem
|
||||
api(this.returnItemFormDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.returnItemFormDialog.visible = false
|
||||
this.loadReturnItems()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteReturnItem(row) {
|
||||
this.$confirm('确定删除该退货明细吗?', '提示').then(() => {
|
||||
return delPurchaseReturnItem(row.returnItemId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadReturnItems()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-purchase-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
.summary-row {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
.summary-card {
|
||||
background: #fdfdfd;
|
||||
border: 1px solid #d9dee4;
|
||||
padding: 16px;
|
||||
height: 90px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.label {
|
||||
color: #5c6b77;
|
||||
font-size: 14px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.value {
|
||||
color: #1f2d3d;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
.panel-card {
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #d0d5d8;
|
||||
background: #fff;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.panel-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.mapping-table {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.mapping-toolbar {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.analysis-table {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.cell-title {
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.cell-sub {
|
||||
color: #7c8792;
|
||||
font-size: 12px;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.toolbar-input {
|
||||
width: 160px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.toolbar-spacer {
|
||||
flex: 1;
|
||||
}
|
||||
.report-block {
|
||||
border: 1px solid #d9dee4;
|
||||
padding: 12px;
|
||||
background: #fafbfc;
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
margin: 0 0 8px;
|
||||
color: #2f3c4c;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
214
klp-ui/src/views/erp/receipt/index.vue
Normal file
214
klp-ui/src/views/erp/receipt/index.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<div class="erp-receipt-page">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>收货记录</span>
|
||||
<el-button type="primary" size="mini" @click="openDialog()">新增收货</el-button>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="query.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-input v-model="query.itemId" placeholder="订单明细ID" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="query.quality" placeholder="质检结果" size="small" clearable class="toolbar-input">
|
||||
<el-option label="合格" value="OK" />
|
||||
<el-option label="不合格" value="NG" />
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" @click="loadData">查询</el-button>
|
||||
<el-button size="small" @click="resetQuery">重置</el-button>
|
||||
</div>
|
||||
<el-table :data="list" border size="small" v-loading="loading">
|
||||
<el-table-column prop="receiptId" label="ID" width="80" />
|
||||
<el-table-column prop="orderId" label="订单ID" width="120" />
|
||||
<el-table-column prop="itemId" label="明细ID" width="120" />
|
||||
<el-table-column prop="receivedQty" label="收货数量" width="120" />
|
||||
<el-table-column prop="qualityResult" label="质检结果" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.qualityResult === 'NG' ? 'danger' : 'success'" size="mini">
|
||||
{{ scope.row.qualityResult || 'OK' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="receiptTime" label="收货时间" width="160" />
|
||||
<el-table-column label="备注" min-width="160" prop="remark" />
|
||||
<el-table-column label="操作" width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="query.pageNum"
|
||||
:limit.sync="query.pageSize"
|
||||
@pagination="loadData"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>到货趋势</span>
|
||||
</div>
|
||||
<el-table :data="chartData" border size="small" height="300">
|
||||
<el-table-column prop="date" label="日期" width="140" />
|
||||
<el-table-column prop="totalQty" label="累计收货(吨)" />
|
||||
<el-table-column prop="qualifiedQty" label="合格数量(吨)" />
|
||||
<el-table-column prop="ngQty" label="不合格(吨)" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-dialog :title="dialog.title" :visible.sync="dialog.visible" width="480px">
|
||||
<el-form :model="dialog.form" :rules="rules" ref="form" label-width="100px" size="small">
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input v-model="dialog.form.orderId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="明细ID" prop="itemId">
|
||||
<el-input v-model="dialog.form.itemId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收货数量" prop="receivedQty">
|
||||
<el-input-number v-model="dialog.form.receivedQty" :min="0" :precision="3" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质检结果">
|
||||
<el-select v-model="dialog.form.qualityResult" clearable>
|
||||
<el-option label="合格" value="OK" />
|
||||
<el-option label="不合格" value="NG" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收货时间">
|
||||
<el-date-picker v-model="dialog.form.receiptTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="dialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="dialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submit">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listPurchaseReceipt,
|
||||
addPurchaseReceipt,
|
||||
updatePurchaseReceipt,
|
||||
delPurchaseReceipt
|
||||
} from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseReceipt',
|
||||
data() {
|
||||
return {
|
||||
query: { pageNum: 1, pageSize: 10, orderId: null, itemId: null },
|
||||
list: [],
|
||||
total: 0,
|
||||
loading: false,
|
||||
chartData: [],
|
||||
dialog: { visible: false, title: '', form: {} },
|
||||
rules: {
|
||||
orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }],
|
||||
itemId: [{ required: true, message: '请输入明细ID', trigger: 'blur' }],
|
||||
receivedQty: [{ required: true, message: '请输入收货数量', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadData()
|
||||
},
|
||||
methods: {
|
||||
loadData() {
|
||||
this.loading = true
|
||||
listPurchaseReceipt(this.query)
|
||||
.then(res => {
|
||||
this.list = res.rows || []
|
||||
this.total = res.total || 0
|
||||
this.buildChart()
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
resetQuery() {
|
||||
this.query = { pageNum: 1, pageSize: 10, orderId: null, itemId: null }
|
||||
this.loadData()
|
||||
},
|
||||
openDialog(row) {
|
||||
if (row) {
|
||||
this.dialog.form = { ...row }
|
||||
this.dialog.title = '编辑收货'
|
||||
} else {
|
||||
this.dialog.form = { orderId: '', itemId: '', receivedQty: 0, qualityResult: 'OK' }
|
||||
this.dialog.title = '新增收货'
|
||||
}
|
||||
this.dialog.visible = true
|
||||
this.$nextTick(() => this.$refs.form && this.$refs.form.clearValidate())
|
||||
},
|
||||
submit() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.dialog.form.receiptId ? updatePurchaseReceipt : addPurchaseReceipt
|
||||
api(this.dialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.dialog.visible = false
|
||||
this.loadData()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$confirm('确定删除该收货记录吗?', '提示').then(() => {
|
||||
return delPurchaseReceipt(row.receiptId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadData()
|
||||
})
|
||||
},
|
||||
buildChart() {
|
||||
const map = {}
|
||||
this.list.forEach(item => {
|
||||
const date = (item.receiptTime || '').slice(0, 10)
|
||||
if (!map[date]) {
|
||||
map[date] = { date, totalQty: 0, qualifiedQty: 0, ngQty: 0 }
|
||||
}
|
||||
map[date].totalQty += Number(item.receivedQty || 0)
|
||||
if (item.qualityResult === 'NG') {
|
||||
map[date].ngQty += Number(item.receivedQty || 0)
|
||||
} else {
|
||||
map[date].qualifiedQty += Number(item.receivedQty || 0)
|
||||
}
|
||||
})
|
||||
this.chartData = Object.values(map).sort((a, b) => a.date.localeCompare(b.date))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-receipt-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #d0d5d8;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.toolbar-input {
|
||||
width: 140px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
</style>
|
||||
|
||||
186
klp-ui/src/views/erp/report/index.vue
Normal file
186
klp-ui/src/views/erp/report/index.vue
Normal file
@@ -0,0 +1,186 @@
|
||||
<template>
|
||||
<div class="erp-report-page">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>采购汇总</span>
|
||||
<el-date-picker
|
||||
v-model="range"
|
||||
type="datetimerange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
size="small"
|
||||
unlink-panels
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束时间"
|
||||
@change="loadSummary"
|
||||
/>
|
||||
</div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="6">
|
||||
<div class="metric-card">
|
||||
<p class="label">采购总金额</p>
|
||||
<p class="value">¥{{ summary.totalAmount | formatMoney }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="metric-card">
|
||||
<p class="label">供应商数量</p>
|
||||
<p class="value">{{ supplierBrief.length }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="metric-card">
|
||||
<p class="label">最大供应商金额</p>
|
||||
<p class="value">¥{{ topSupplierAmount | formatMoney }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="metric-card">
|
||||
<p class="label">平均订单金额</p>
|
||||
<p class="value">¥{{ avgSupplierAmount | formatMoney }}</p>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>供应商汇总</span>
|
||||
</div>
|
||||
<el-table :data="supplierBrief" border size="small" height="320">
|
||||
<el-table-column prop="supplierId" label="供应商ID" width="140" />
|
||||
<el-table-column prop="orderCount" label="订单数" width="100" />
|
||||
<el-table-column prop="totalAmount" label="总金额" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>价格趋势</span>
|
||||
</div>
|
||||
<el-table :data="priceTrend" border size="small" height="320">
|
||||
<el-table-column prop="period" label="月份" width="120" />
|
||||
<el-table-column prop="materialCode" label="物料编码" width="140" />
|
||||
<el-table-column prop="avgPrice" label="平均含税价" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>供应商退货率</span>
|
||||
</div>
|
||||
<el-table :data="supplierQuality" border size="small" height="320">
|
||||
<el-table-column prop="supplierId" label="供应商ID" width="140" />
|
||||
<el-table-column prop="receivedQty" label="收货量" />
|
||||
<el-table-column prop="returnQty" label="退货量" />
|
||||
<el-table-column label="退货率">
|
||||
<template slot-scope="scope">
|
||||
{{ formatPercent(scope.row.returnRate) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getPurchaseReportSummary, getPurchasePriceTrend, getSupplierQuality } from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseReport',
|
||||
data() {
|
||||
return {
|
||||
range: [],
|
||||
summary: { totalAmount: 0 },
|
||||
supplierBrief: [],
|
||||
priceTrend: [],
|
||||
supplierQuality: []
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatMoney(value) {
|
||||
return Number(value || 0).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
topSupplierAmount() {
|
||||
if (!this.supplierBrief.length) return 0
|
||||
return Math.max(...this.supplierBrief.map(item => Number(item.totalAmount || 0)))
|
||||
},
|
||||
avgSupplierAmount() {
|
||||
if (!this.supplierBrief.length) return 0
|
||||
const sum = this.supplierBrief.reduce((acc, cur) => acc + Number(cur.totalAmount || 0), 0)
|
||||
return sum / this.supplierBrief.length
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadSummary()
|
||||
},
|
||||
methods: {
|
||||
buildParams() {
|
||||
const params = {}
|
||||
if (this.range && this.range.length === 2) {
|
||||
params.beginTime = this.range[0]
|
||||
params.endTime = this.range[1]
|
||||
}
|
||||
return params
|
||||
},
|
||||
loadSummary() {
|
||||
const params = this.buildParams()
|
||||
getPurchaseReportSummary(params).then(res => {
|
||||
this.summary = { totalAmount: res.totalAmount || 0 }
|
||||
this.supplierBrief = res.bySupplier || []
|
||||
})
|
||||
getPurchasePriceTrend(params).then(res => {
|
||||
this.priceTrend = res || []
|
||||
})
|
||||
getSupplierQuality(params).then(res => {
|
||||
this.supplierQuality = res || []
|
||||
})
|
||||
},
|
||||
formatPercent(value) {
|
||||
if (!value || !isFinite(value)) return '0%'
|
||||
return `${(Number(value) * 100).toFixed(2)}%`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-report-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #d0d5d8;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.metric-card {
|
||||
border: 1px solid #d9dee4;
|
||||
padding: 16px;
|
||||
background: #fff;
|
||||
.label {
|
||||
color: #5b6875;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.value {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
201
klp-ui/src/views/erp/requirement/index.vue
Normal file
201
klp-ui/src/views/erp/requirement/index.vue
Normal file
@@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="erp-requirement-page">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>采购需求分析</span>
|
||||
<div class="panel-actions">
|
||||
<el-switch v-model="persistResult" active-text="写入建议表" inactive-text="仅计算" />
|
||||
<el-button type="primary" size="mini" @click="handleAnalyze" :loading="loading">执行分析</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table :data="mappingRows" border size="small" class="mapping-table">
|
||||
<el-table-column label="产品ID" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.productId" placeholder="产品ID" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="原料ID" width="180">
|
||||
<template slot-scope="scope">
|
||||
<el-input v-model="scope.row.rawMaterialId" placeholder="原料ID" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="转换率" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-input-number v-model="scope.row.conversionRate" :min="0" :max="1" :step="0.01" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click="removeMapping(scope.$index)" :disabled="mappingRows.length === 1">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button icon="el-icon-plus" size="mini" class="add-btn" @click="addMapping">新增映射</el-button>
|
||||
|
||||
<el-table
|
||||
:data="resultList"
|
||||
border
|
||||
size="small"
|
||||
v-loading="loading"
|
||||
show-summary
|
||||
:summary-method="summaryMethod"
|
||||
>
|
||||
<el-table-column label="产品" width="220">
|
||||
<template slot-scope="scope">
|
||||
<div class="title">{{ scope.row.productName || '-' }}</div>
|
||||
<div class="cell-sub">ID: {{ scope.row.productId || '-' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="specification" label="规格" width="160" />
|
||||
<el-table-column prop="salesDemand" label="销售需求(吨)" width="140" />
|
||||
<el-table-column prop="productStockWeight" label="成品库存(吨)" width="140" />
|
||||
<el-table-column prop="rawStockConverted" label="原料折算(吨)" width="140" />
|
||||
<el-table-column prop="inTransitConverted" label="在途折算(吨)" width="140" />
|
||||
<el-table-column prop="pendingConverted" label="待下达折算(吨)" width="140" />
|
||||
<el-table-column prop="suggestedPurchase" label="建议采购(吨)" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span :class="scope.row.suggestedPurchase > 0 ? 'highlight' : ''">
|
||||
{{ scope.row.suggestedPurchase }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>原料折算详情</span>
|
||||
</div>
|
||||
<el-table :data="rawDetailData" size="small" border height="320">
|
||||
<el-table-column prop="productName" label="产品" width="200" />
|
||||
<el-table-column prop="rawMaterialName" label="原料" width="200" />
|
||||
<el-table-column prop="conversionRate" label="转换率" width="120" />
|
||||
<el-table-column prop="stockWeight" label="库存重量" width="120" />
|
||||
<el-table-column prop="stockCoilCount" label="库存卷数" width="120" />
|
||||
<el-table-column prop="convertedStock" label="折算库存" width="120" />
|
||||
<el-table-column prop="convertedInTransit" label="折算在途" width="120" />
|
||||
<el-table-column prop="convertedPending" label="折算待下达" width="120" />
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { analyzePurchaseRequirement } from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseRequirement',
|
||||
data() {
|
||||
return {
|
||||
mappingRows: [{ productId: '', rawMaterialId: '', conversionRate: 1 }],
|
||||
persistResult: false,
|
||||
loading: false,
|
||||
resultList: [],
|
||||
rawDetailData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addMapping() {
|
||||
this.mappingRows.push({ productId: '', rawMaterialId: '', conversionRate: 1 })
|
||||
},
|
||||
removeMapping(idx) {
|
||||
if (this.mappingRows.length === 1) return
|
||||
this.mappingRows.splice(idx, 1)
|
||||
},
|
||||
handleAnalyze() {
|
||||
if (!this.mappingRows.every(row => row.productId && row.rawMaterialId)) {
|
||||
this.$message.warning('请完善产品与原料映射')
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
analyzePurchaseRequirement({
|
||||
persistResult: this.persistResult,
|
||||
mappings: this.mappingRows.map(row => ({
|
||||
productId: Number(row.productId),
|
||||
rawMaterialId: Number(row.rawMaterialId),
|
||||
conversionRate: Number(row.conversionRate || 0)
|
||||
}))
|
||||
})
|
||||
.then(res => {
|
||||
this.resultList = res || []
|
||||
this.buildRawDetail(res || [])
|
||||
this.$message.success('分析完成')
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
buildRawDetail(list) {
|
||||
const rows = []
|
||||
list.forEach(item => {
|
||||
(item.rawDetails || []).forEach(detail => {
|
||||
rows.push({
|
||||
productName: item.productName,
|
||||
rawMaterialName: detail.rawMaterialName,
|
||||
conversionRate: detail.conversionRate,
|
||||
stockWeight: detail.stockWeight,
|
||||
stockCoilCount: detail.stockCoilCount,
|
||||
convertedStock: detail.convertedStock,
|
||||
convertedInTransit: detail.convertedInTransit,
|
||||
convertedPending: detail.convertedPending
|
||||
})
|
||||
})
|
||||
})
|
||||
this.rawDetailData = rows
|
||||
},
|
||||
summaryMethod({ data }) {
|
||||
const sums = []
|
||||
const fields = ['salesDemand', 'productStockWeight', 'rawStockConverted', 'inTransitConverted', 'pendingConverted', 'suggestedPurchase']
|
||||
sums[0] = '总计'
|
||||
data.forEach(row => {
|
||||
fields.forEach((field, idx) => {
|
||||
sums[idx + 2] = (Number(sums[idx + 2]) || 0) + Number(row[field] || 0)
|
||||
})
|
||||
})
|
||||
return sums
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-requirement-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid #d0d5d8;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.panel-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.mapping-table {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.add-btn {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.title {
|
||||
font-weight: 600;
|
||||
}
|
||||
.cell-sub {
|
||||
color: #7c8792;
|
||||
font-size: 12px;
|
||||
}
|
||||
.highlight {
|
||||
color: #c0392b;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
|
||||
295
klp-ui/src/views/erp/return/index.vue
Normal file
295
klp-ui/src/views/erp/return/index.vue
Normal file
@@ -0,0 +1,295 @@
|
||||
<template>
|
||||
<div class="erp-return-page">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="13">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>退货单</span>
|
||||
<el-button type="primary" size="mini" @click="openReturnDialog()">新增退货单</el-button>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="returnQuery.orderId" placeholder="订单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="returnQuery.status" placeholder="状态" size="small" clearable class="toolbar-input">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="完成" :value="1" />
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" @click="loadReturns">查询</el-button>
|
||||
<el-button size="small" @click="resetReturnQuery">重置</el-button>
|
||||
</div>
|
||||
<el-table :data="returnList" border size="small" v-loading="returnLoading" height="420">
|
||||
<el-table-column prop="returnId" label="退货单ID" width="120" />
|
||||
<el-table-column prop="orderId" label="订单ID" width="120" />
|
||||
<el-table-column prop="returnType" label="类型" width="120" />
|
||||
<el-table-column prop="reason" label="原因" min-width="160" />
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.status === 1 ? 'success' : 'info'" size="mini">
|
||||
{{ scope.row.status === 1 ? '完成' : '草稿' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openReturnDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="openReturnItems(scope.row)">明细</el-button>
|
||||
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDeleteReturn(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="11">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>退货明细</span>
|
||||
<el-button type="primary" size="mini" @click="openReturnItemDialog()">新增明细</el-button>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="returnItemQuery.returnId" placeholder="退货单ID" size="small" clearable class="toolbar-input" />
|
||||
<el-input v-model="returnItemQuery.itemId" placeholder="订单明细ID" size="small" clearable class="toolbar-input" />
|
||||
<el-button size="small" type="primary" @click="loadReturnItems">查询</el-button>
|
||||
<el-button size="small" @click="resetReturnItemQuery">重置</el-button>
|
||||
</div>
|
||||
<el-table :data="returnItemList" border size="small" height="420" v-loading="returnItemLoading">
|
||||
<el-table-column prop="returnItemId" label="ID" width="80" />
|
||||
<el-table-column prop="returnId" label="退货单ID" width="120" />
|
||||
<el-table-column prop="itemId" label="订单明细ID" width="150" />
|
||||
<el-table-column prop="returnQty" label="数量" width="100" />
|
||||
<el-table-column label="问题照片" min-width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip v-if="scope.row.photos" :content="scope.row.photos" placement="top">
|
||||
<span class="link">查看</span>
|
||||
</el-tooltip>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="140">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openReturnItemDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" style="color:#c0392b" @click="handleDeleteReturnItem(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-dialog :title="returnDialog.title" :visible.sync="returnDialog.visible" width="520px">
|
||||
<el-form :model="returnDialog.form" :rules="returnRules" ref="returnForm" label-width="100px" size="small">
|
||||
<el-form-item label="订单ID" prop="orderId">
|
||||
<el-input v-model="returnDialog.form.orderId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退货类型">
|
||||
<el-select v-model="returnDialog.form.returnType">
|
||||
<el-option label="质量问题" value="QUALITY" />
|
||||
<el-option label="数量错误" value="QTY" />
|
||||
<el-option label="规格不符" value="SPEC" />
|
||||
<el-option label="协商退货" value="OTHER" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="退货原因">
|
||||
<el-input type="textarea" v-model="returnDialog.form.reason" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="returnDialog.form.status">
|
||||
<el-option label="草稿" :value="0" />
|
||||
<el-option label="完成" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="returnDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="returnDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitReturn">保 存</el按钮>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog :title="returnItemDialog.title" :visible.sync="returnItemDialog.visible" width="500px">
|
||||
<el-form :model="returnItemDialog.form" :rules="returnItemRules" ref="returnItemForm" label-width="120px" size="small">
|
||||
<el-form-item label="退货单ID" prop="returnId">
|
||||
<el-input v-model="returnItemDialog.form.returnId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="订单明细ID" prop="itemId">
|
||||
<el-input v-model="returnItemDialog.form.itemId" />
|
||||
</el-form-item>
|
||||
<el-form-item label="退货数量" prop="returnQty">
|
||||
<el-input-number v-model="returnItemDialog.form.returnQty" :min="0" :precision="3" />
|
||||
</el-form-item>
|
||||
<el-form-item label="问题照片">
|
||||
<el-input v-model="returnItemDialog.form.photos" placeholder="多张以逗号分隔" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="returnItemDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="returnItemDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitReturnItem">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listPurchaseReturn,
|
||||
addPurchaseReturn,
|
||||
updatePurchaseReturn,
|
||||
delPurchaseReturn,
|
||||
listPurchaseReturnItem,
|
||||
addPurchaseReturnItem,
|
||||
updatePurchaseReturnItem,
|
||||
delPurchaseReturnItem
|
||||
} from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpPurchaseReturn',
|
||||
data() {
|
||||
return {
|
||||
returnQuery: { pageNum: 1, pageSize: 10, orderId: null, status: null },
|
||||
returnList: [],
|
||||
returnLoading: false,
|
||||
returnDialog: { visible: false, title: '', form: {} },
|
||||
returnRules: { orderId: [{ required: true, message: '请输入订单ID', trigger: 'blur' }] },
|
||||
returnItemQuery: { pageNum: 1, pageSize: 10, returnId: null, itemId: null },
|
||||
returnItemList: [],
|
||||
returnItemLoading: false,
|
||||
returnItemDialog: { visible: false, title: '', form: {} },
|
||||
returnItemRules: {
|
||||
returnId: [{ required: true, message: '请输入退货单ID', trigger: 'blur' }],
|
||||
itemId: [{ required: true, message: '请输入订单明细ID', trigger: 'blur' }],
|
||||
returnQty: [{ required: true, message: '请输入退货数量', trigger: 'blur' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadReturns()
|
||||
this.loadReturnItems()
|
||||
},
|
||||
methods: {
|
||||
loadReturns() {
|
||||
this.returnLoading = true
|
||||
listPurchaseReturn(this.returnQuery)
|
||||
.then(res => {
|
||||
this.returnList = res.rows || []
|
||||
})
|
||||
.finally(() => {
|
||||
this.returnLoading = false
|
||||
})
|
||||
},
|
||||
resetReturnQuery() {
|
||||
this.returnQuery = { pageNum: 1, pageSize: 10, orderId: null, status: null }
|
||||
this.loadReturns()
|
||||
},
|
||||
openReturnDialog(row) {
|
||||
if (row) {
|
||||
this.returnDialog.form = { ...row }
|
||||
this.returnDialog.title = '编辑退货单'
|
||||
} else {
|
||||
this.returnDialog.form = { orderId: '', returnType: 'QUALITY', status: 0 }
|
||||
this.returnDialog.title = '新增退货单'
|
||||
}
|
||||
this.returnDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.returnForm && this.$refs.returnForm.clearValidate())
|
||||
},
|
||||
submitReturn() {
|
||||
this.$refs.returnForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.returnDialog.form.returnId ? updatePurchaseReturn : addPurchaseReturn
|
||||
api(this.returnDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.returnDialog.visible = false
|
||||
this.loadReturns()
|
||||
})
|
||||
})
|
||||
},
|
||||
openReturnItems(row) {
|
||||
this.returnItemQuery.returnId = row.returnId
|
||||
this.loadReturnItems()
|
||||
},
|
||||
handleDeleteReturn(row) {
|
||||
this.$confirm('确定删除该退货单吗?', '提示').then(() => delPurchaseReturn(row.returnId)).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadReturns()
|
||||
})
|
||||
},
|
||||
loadReturnItems() {
|
||||
this.returnItemLoading = true
|
||||
listPurchaseReturnItem(this.returnItemQuery)
|
||||
.then(res => {
|
||||
this.returnItemList = res.rows || []
|
||||
})
|
||||
.finally(() => {
|
||||
this.returnItemLoading = false
|
||||
})
|
||||
},
|
||||
resetReturnItemQuery() {
|
||||
this.returnItemQuery = { pageNum: 1, pageSize: 10, returnId: null, itemId: null }
|
||||
this.loadReturnItems()
|
||||
},
|
||||
openReturnItemDialog(row) {
|
||||
if (row) {
|
||||
this.returnItemDialog.form = { ...row }
|
||||
this.returnItemDialog.title = '编辑退货明细'
|
||||
} else {
|
||||
this.returnItemDialog.form = { returnId: this.returnItemQuery.returnId || '', itemId: '', returnQty: 0 }
|
||||
this.returnItemDialog.title = '新增退货明细'
|
||||
}
|
||||
this.returnItemDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.returnItemForm && this.$refs.returnItemForm.clearValidate())
|
||||
},
|
||||
submitReturnItem() {
|
||||
this.$refs.returnItemForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.returnItemDialog.form.returnItemId ? updatePurchaseReturnItem : addPurchaseReturnItem
|
||||
api(this.returnItemDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.returnItemDialog.visible = false
|
||||
this.loadReturnItems()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteReturnItem(row) {
|
||||
this.$confirm('确定删除该明细吗?', '提示').then(() => delPurchaseReturnItem(row.returnItemId)).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadReturnItems()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-return-page {
|
||||
padding: 16px;
|
||||
background: #eef1f3;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
border: 1px solid #d0d5d8;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.toolbar-input {
|
||||
width: 140px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.link {
|
||||
color: #2f86d7;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
340
klp-ui/src/views/erp/supplier/index.vue
Normal file
340
klp-ui/src/views/erp/supplier/index.vue
Normal file
@@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<div class="erp-supplier-page">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="10">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>供应商档案</span>
|
||||
<el-button type="primary" size="mini" @click="openSupplierDialog()">新增</el-button>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="supplierQuery.name" placeholder="供应商名称" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="supplierQuery.creditRating" placeholder="信用等级" size="small" clearable class="toolbar-input">
|
||||
<el-option label="A" value="A" />
|
||||
<el-option label="B" value="B" />
|
||||
<el-option label="C" value="C" />
|
||||
<el-option label="D" value="D" />
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" @click="loadSuppliers">查询</el-button>
|
||||
<el-button size="small" @click="resetSupplierQuery">重置</el-button>
|
||||
</div>
|
||||
<el-table :data="supplierList" height="420" size="small" border v-loading="supplierLoading">
|
||||
<el-table-column prop="supplierCode" label="编码" width="120" />
|
||||
<el-table-column prop="name" label="名称" min-width="160" />
|
||||
<el-table-column prop="creditRating" label="信用" width="80" />
|
||||
<el-table-column label="联系人" width="140">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.contactPerson || '-' }}</div>
|
||||
<div class="cell-sub">{{ scope.row.contactPhone || '' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openSupplierDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeleteSupplier(scope.row)" style="color:#c0392b">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-card shadow="never" class="panel-card">
|
||||
<div slot="header" class="panel-header">
|
||||
<span>供应商价格表</span>
|
||||
<el-button type="primary" size="mini" @click="openPriceDialog()">新增价格</el-button>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="priceQuery.materialTypeCode" placeholder="物料编码" size="small" clearable class="toolbar-input" />
|
||||
<el-select v-model="priceQuery.supplierId" placeholder="供应商" size="small" clearable class="toolbar-input">
|
||||
<el-option v-for="sp in supplierOptions" :key="sp.supplierId" :label="sp.name" :value="sp.supplierId" />
|
||||
</el-select>
|
||||
<el-date-picker v-model="priceRange" type="daterange" value-format="yyyy-MM-dd" size="small" range-separator="至"
|
||||
start-placeholder="生效日期" end-placeholder="失效日期" />
|
||||
<el-button size="small" type="primary" @click="loadPrices">查询</el-button>
|
||||
</div>
|
||||
<el-table :data="priceList" size="small" border v-loading="priceLoading">
|
||||
<el-table-column prop="supplierId" label="供应商" width="150">
|
||||
<template slot-scope="scope">
|
||||
{{ matchSupplier(scope.row.supplierId) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="materialTypeCode" label="物料类型" width="160" />
|
||||
<el-table-column prop="specification" label="规格" min-width="140" />
|
||||
<el-table-column prop="price" label="价格(含税)" width="110" />
|
||||
<el-table-column label="有效期" width="200">
|
||||
<template slot-scope="scope">
|
||||
<div>{{ scope.row.validFrom || '-' }}</div>
|
||||
<div class="cell-sub">{{ scope.row.validTo || '-' }}</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="160">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="mini" @click="openPriceDialog(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" @click="handleDeletePrice(scope.row)" style="color:#c0392b">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 供应商弹窗 -->
|
||||
<el-dialog :title="supplierDialog.title" :visible.sync="supplierDialog.visible" width="520px">
|
||||
<el-form :model="supplierDialog.form" :rules="supplierRules" ref="supplierForm" label-width="90px" size="small">
|
||||
<el-form-item label="编码" prop="supplierCode">
|
||||
<el-input v-model="supplierDialog.form.supplierCode" />
|
||||
</el-form-item>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="supplierDialog.form.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型">
|
||||
<el-input v-model="supplierDialog.form.type" />
|
||||
</el-form-item>
|
||||
<el-form-item label="信用等级">
|
||||
<el-select v-model="supplierDialog.form.creditRating" clearable>
|
||||
<el-option label="A" value="A" />
|
||||
<el-option label="B" value="B" />
|
||||
<el-option label="C" value="C" />
|
||||
<el-option label="D" value="D" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系人">
|
||||
<el-input v-model="supplierDialog.form.contactPerson" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话">
|
||||
<el-input v-model="supplierDialog.form.contactPhone" />
|
||||
</el-form-item>
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="supplierDialog.form.address" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="supplierDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="supplierDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitSupplier">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 价格弹窗 -->
|
||||
<el-dialog :title="priceDialog.title" :visible.sync="priceDialog.visible" width="520px">
|
||||
<el-form :model="priceDialog.form" :rules="priceRules" ref="priceForm" label-width="100px" size="small">
|
||||
<el-form-item label="供应商" prop="supplierId">
|
||||
<el-select v-model="priceDialog.form.supplierId" placeholder="选择供应商">
|
||||
<el-option v-for="sp in supplierOptions" :key="sp.supplierId" :label="sp.name" :value="sp.supplierId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="物料类型" prop="materialTypeCode">
|
||||
<el-input v-model="priceDialog.form.materialTypeCode" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格">
|
||||
<el-input v-model="priceDialog.form.specification" />
|
||||
</el-form-item>
|
||||
<el-form-item label="含税价格" prop="price">
|
||||
<el-input-number v-model="priceDialog.form.price" :min="0" :precision="2" />
|
||||
</el-form-item>
|
||||
<el-form-item label="有效期">
|
||||
<el-date-picker
|
||||
v-model="priceValidRange"
|
||||
type="daterange"
|
||||
value-format="yyyy-MM-dd"
|
||||
start-placeholder="开始"
|
||||
end-placeholder="结束"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="priceDialog.form.remark" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button @click="priceDialog.visible = false">取 消</el-button>
|
||||
<el-button type="primary" @click="submitPrice">保 存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
listSupplier,
|
||||
addSupplier,
|
||||
updateSupplier,
|
||||
delSupplier,
|
||||
listSupplierPrice,
|
||||
addSupplierPrice,
|
||||
updateSupplierPrice,
|
||||
delSupplierPrice
|
||||
} from '@/api/erp/purchase'
|
||||
|
||||
export default {
|
||||
name: 'ErpSupplierManage',
|
||||
data() {
|
||||
return {
|
||||
supplierQuery: { pageNum: 1, pageSize: 50, name: null, creditRating: null },
|
||||
supplierList: [],
|
||||
supplierLoading: false,
|
||||
supplierDialog: { visible: false, title: '', form: {} },
|
||||
supplierRules: {
|
||||
supplierCode: [{ required: true, message: '请输入编码', trigger: 'blur' }],
|
||||
name: [{ required: true, message: '请输入名称', trigger: 'blur' }]
|
||||
},
|
||||
priceQuery: { pageNum: 1, pageSize: 50, supplierId: null, materialTypeCode: null },
|
||||
priceList: [],
|
||||
priceLoading: false,
|
||||
priceDialog: { visible: false, title: '', form: {} },
|
||||
priceRules: {
|
||||
supplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }],
|
||||
materialTypeCode: [{ required: true, message: '请输入物料类型', trigger: 'blur' }],
|
||||
price: [{ required: true, message: '请输入价格', trigger: 'change' }]
|
||||
},
|
||||
priceRange: [],
|
||||
priceValidRange: [],
|
||||
supplierOptions: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadSuppliers()
|
||||
this.loadPrices()
|
||||
},
|
||||
methods: {
|
||||
loadSuppliers() {
|
||||
this.supplierLoading = true
|
||||
listSupplier(this.supplierQuery)
|
||||
.then(res => {
|
||||
this.supplierList = res.rows || []
|
||||
this.supplierOptions = this.supplierList
|
||||
})
|
||||
.finally(() => {
|
||||
this.supplierLoading = false
|
||||
})
|
||||
},
|
||||
resetSupplierQuery() {
|
||||
this.supplierQuery = { pageNum: 1, pageSize: 50, name: null, creditRating: null }
|
||||
this.loadSuppliers()
|
||||
},
|
||||
openSupplierDialog(row) {
|
||||
if (row) {
|
||||
this.supplierDialog.form = { ...row }
|
||||
this.supplierDialog.title = '编辑供应商'
|
||||
} else {
|
||||
this.supplierDialog.form = { supplierCode: '', name: '', creditRating: 'A' }
|
||||
this.supplierDialog.title = '新增供应商'
|
||||
}
|
||||
this.supplierDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.supplierForm && this.$refs.supplierForm.clearValidate())
|
||||
},
|
||||
submitSupplier() {
|
||||
this.$refs.supplierForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const api = this.supplierDialog.form.supplierId ? updateSupplier : addSupplier
|
||||
api(this.supplierDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.supplierDialog.visible = false
|
||||
this.loadSuppliers()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeleteSupplier(row) {
|
||||
this.$confirm('确认删除该供应商吗?', '提示').then(() => {
|
||||
return delSupplier(row.supplierId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadSuppliers()
|
||||
})
|
||||
},
|
||||
// price
|
||||
loadPrices() {
|
||||
const query = { ...this.priceQuery }
|
||||
if (this.priceRange && this.priceRange.length === 2) {
|
||||
query.beginTime = this.priceRange[0]
|
||||
query.endTime = this.priceRange[1]
|
||||
}
|
||||
this.priceLoading = true
|
||||
listSupplierPrice(query)
|
||||
.then(res => {
|
||||
this.priceList = res.rows || []
|
||||
})
|
||||
.finally(() => {
|
||||
this.priceLoading = false
|
||||
})
|
||||
},
|
||||
matchSupplier(id) {
|
||||
const target = this.supplierOptions.find(sp => sp.supplierId === id)
|
||||
return target ? target.name : id
|
||||
},
|
||||
openPriceDialog(row) {
|
||||
if (!this.supplierOptions.length) {
|
||||
this.$message.warning('请先维护供应商')
|
||||
return
|
||||
}
|
||||
if (row) {
|
||||
this.priceDialog.form = { ...row }
|
||||
this.priceValidRange = [row.validFrom, row.validTo]
|
||||
this.priceDialog.title = '编辑价格'
|
||||
} else {
|
||||
this.priceDialog.form = { supplierId: null, materialTypeCode: '', price: 0 }
|
||||
this.priceValidRange = []
|
||||
this.priceDialog.title = '新增价格'
|
||||
}
|
||||
this.priceDialog.visible = true
|
||||
this.$nextTick(() => this.$refs.priceForm && this.$refs.priceForm.clearValidate())
|
||||
},
|
||||
submitPrice() {
|
||||
this.$refs.priceForm.validate(valid => {
|
||||
if (!valid) return
|
||||
if (this.priceValidRange && this.priceValidRange.length === 2) {
|
||||
this.priceDialog.form.validFrom = this.priceValidRange[0]
|
||||
this.priceDialog.form.validTo = this.priceValidRange[1]
|
||||
}
|
||||
const api = this.priceDialog.form.priceId ? updateSupplierPrice : addSupplierPrice
|
||||
api(this.priceDialog.form).then(() => {
|
||||
this.$message.success('保存成功')
|
||||
this.priceDialog.visible = false
|
||||
this.loadPrices()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDeletePrice(row) {
|
||||
this.$confirm('确认删除该价格吗?', '提示').then(() => {
|
||||
return delSupplierPrice(row.priceId)
|
||||
}).then(() => {
|
||||
this.$message.success('删除成功')
|
||||
this.loadPrices()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.erp-supplier-page {
|
||||
background: #eef1f3;
|
||||
padding: 16px;
|
||||
min-height: 100%;
|
||||
}
|
||||
.panel-card {
|
||||
border: 1px solid #d0d5d8;
|
||||
}
|
||||
.panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
color: #1f2d3d;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.toolbar-input {
|
||||
width: 150px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.cell-sub {
|
||||
font-size: 12px;
|
||||
color: #7c8792;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user