增加专属报价功能

This commit is contained in:
wuweihua
2026-11-05 12:57:13 +08:00
parent 557d43a0b8
commit 308526ecee
32 changed files with 3817 additions and 567 deletions
@@ -0,0 +1,453 @@
package com.bms.web.controller.price;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.bms.price.service.support.UploadFileBatch;
import com.bms.common.annotation.Log;
import com.bms.common.core.controller.BaseController;
import com.bms.common.core.domain.AjaxResult;
import com.bms.common.core.page.TableDataInfo;
import com.bms.common.enums.BusinessType;
import com.bms.common.utils.MessageUtils;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.PrcCustomerPriceSet;
import com.bms.price.domain.PrcCustomerPriceSetBatch;
import com.bms.price.domain.PrcPriceExcelFile;
import com.bms.price.domain.PrcPriceSet;
import com.bms.price.domain.PrcPriceSetDetail;
import com.bms.price.domain.PrcPriceSetSaveTask;
import com.bms.price.domain.PrcPriceSetVersion;
import com.bms.price.service.IPrcPriceExcelFileService;
import com.bms.price.service.IPrcPriceSetService;
/**
* Exclusive quote (shares prc_price_set with PACKAGE)
*
* @author bms
*/
@RestController
@RequestMapping("/price/exclusive")
public class ExclusiveQuoteController extends BaseController
{
@Autowired
private IPrcPriceSetService priceSetService;
@Autowired
private IPrcPriceExcelFileService priceExcelFileService;
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/list")
public TableDataInfo list(PrcPriceSet set)
{
set.setSetCategory(PrcPriceSet.CATEGORY_EXCLUSIVE);
startPage();
List<PrcPriceSet> list = priceSetService.selectPrcPriceSetList(set);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:query')")
@GetMapping("/{priceSetId:[0-9]+}")
public AjaxResult getInfo(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return success(priceSetService.selectPrcPriceSetById(priceSetId));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:add')")
@Log(title = "Exclusive quote", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody PrcPriceSet set)
{
if (set.getPriceSetId() != null)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_EXCLUSIVE);
}
set.setSetCategory(PrcPriceSet.CATEGORY_EXCLUSIVE);
set.setCreateBy(getUsername());
set.setUpdateBy(getUsername());
String taskId = priceSetService.submitSaveAsync(set);
// Do not pass bare String to success(): overload puts it into msg, not data.
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:query')")
@GetMapping("/save/task/{taskId}")
public AjaxResult getSaveTask(@PathVariable String taskId)
{
PrcPriceSetSaveTask task = priceSetService.getSaveTask(taskId);
if (task == null)
{
return error(MessageUtils.message("price.set.save.task.notExists"));
}
return success(task);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@Validated @RequestBody PrcPriceSet set)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_EXCLUSIVE);
set.setSetCategory(PrcPriceSet.CATEGORY_EXCLUSIVE);
set.setUpdateBy(getUsername());
return toAjax(priceSetService.updatePrcPriceSet(set));
}
/** Update package name and note only. */
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote basic", businessType = BusinessType.UPDATE)
@PutMapping("/basic")
public AjaxResult editBasic(@RequestBody PrcPriceSet set)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_EXCLUSIVE);
set.setUpdateBy(getUsername());
return toAjax(priceSetService.updateBasicInfo(set));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:remove')")
@Log(title = "Exclusive quote", businessType = BusinessType.DELETE)
@DeleteMapping("/{priceSetIds}")
public AjaxResult remove(@PathVariable Long[] priceSetIds)
{
if (priceSetIds != null)
{
for (Long id : priceSetIds)
{
priceSetService.assertSetCategory(id, PrcPriceSet.CATEGORY_EXCLUSIVE);
}
}
return toAjax(priceSetService.deletePrcPriceSetByIds(priceSetIds));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:audit')")
@Log(title = "Exclusive quote提交审核", businessType = BusinessType.UPDATE)
@PutMapping("/submit/{priceSetId}")
public AjaxResult submit(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return toAjax(priceSetService.submit(priceSetId, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:audit')")
@Log(title = "Exclusive quote生效", businessType = BusinessType.UPDATE)
@PutMapping("/approve/{priceSetId}")
public AjaxResult approve(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return toAjax(priceSetService.approve(priceSetId, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:audit')")
@Log(title = "Exclusive quote驳回", businessType = BusinessType.UPDATE)
@PutMapping("/reject/{priceSetId}")
public AjaxResult reject(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return toAjax(priceSetService.reject(priceSetId, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote version activate", businessType = BusinessType.UPDATE)
@PutMapping("/version/activate/{psvId}")
public AjaxResult activateVersion(@PathVariable Long psvId, @RequestBody(required = false) PrcPriceSetVersion body)
{
Date effectiveTime = body == null ? null : body.getEffectiveTime();
return toAjax(priceSetService.activateVersion(psvId, effectiveTime, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:add')")
@Log(title = "Exclusive quote version copy", businessType = BusinessType.INSERT)
@PostMapping("/version/copy/{psvId}")
public AjaxResult copyVersion(@PathVariable Long psvId)
{
Long newPsvId = priceSetService.copyVersion(psvId, getUsername());
return success(newPsvId);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:add')")
@Log(title = "Exclusive quote version create", businessType = BusinessType.INSERT)
@PostMapping("/version/create/{priceSetId}")
public AjaxResult createVersion(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
Long newPsvId = priceSetService.createVersion(priceSetId, getUsername());
return success(newPsvId);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote version delete", businessType = BusinessType.DELETE)
@DeleteMapping("/version/{psvId}")
public AjaxResult deleteVersion(@PathVariable Long psvId)
{
return toAjax(priceSetService.deleteVersion(psvId, getUsername()));
}
/** Import excel attachments for a version (prc_price_excel_file.psv_id). */
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/version/{psvId}/excelFiles")
public AjaxResult versionExcelFiles(@PathVariable Long psvId)
{
List<PrcPriceExcelFile> list = priceExcelFileService.selectByPsvId(psvId);
return success(list);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:audit')")
@Log(title = "Exclusive quote disable", businessType = BusinessType.UPDATE)
@PutMapping("/disable/{priceSetId}")
public AjaxResult disable(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return toAjax(priceSetService.disable(priceSetId, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:audit')")
@Log(title = "Exclusive quote enable", businessType = BusinessType.UPDATE)
@PutMapping("/enable/{priceSetId}")
public AjaxResult enable(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
return toAjax(priceSetService.enable(priceSetId, getUsername()));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:add')")
@Log(title = "Exclusive quote copy", businessType = BusinessType.INSERT)
@PostMapping("/copy/{priceSetId}")
public AjaxResult copy(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
Long id = priceSetService.copy(priceSetId, getUsername());
return success(id);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:query')")
@PostMapping("/validate")
public AjaxResult validate(@RequestBody PrcPriceSet set)
{
return success(priceSetService.validate(set));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/detail/list")
public TableDataInfo detailList(PrcPriceSetDetail detail)
{
startPage();
List<PrcPriceSetDetail> list = priceSetService.selectDetailList(detail);
return getDataTable(list);
}
/** All detail rows for one product (no page); used by edit-price drawer. */
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/detail/byProduct")
public AjaxResult detailByProduct(@RequestParam("psvId") Long psvId,
@RequestParam("productCode") String productCode)
{
return success(priceSetService.selectDetailListByProduct(psvId, productCode));
}
/** All detail rows for a version (no page); batch prefetch instead of N byProduct calls. */
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/detail/byVersion")
public AjaxResult detailByVersion(@RequestParam("psvId") Long psvId)
{
return success(priceSetService.selectDetailListByVersion(psvId));
}
/**
* 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区
*/
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/detail/options")
public AjaxResult detailOptions(@RequestParam("psvId") Long psvId)
{
return success(priceSetService.selectDetailOptions(psvId));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote明细", businessType = BusinessType.INSERT)
@PostMapping("/detail")
public AjaxResult addDetail(@RequestBody PrcPriceSetDetail detail)
{
return toAjax(priceSetService.insertDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote明细", businessType = BusinessType.UPDATE)
@PutMapping("/detail")
public AjaxResult editDetail(@RequestBody PrcPriceSetDetail detail)
{
return toAjax(priceSetService.updateDetail(detail));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote价格导入", businessType = BusinessType.IMPORT)
@PostMapping("/detail/importPrices")
public AjaxResult importDetailPrices(
@RequestParam(value = "files", required = false) MultipartFile[] files,
@RequestParam(value = "file", required = false) MultipartFile file,
@RequestParam("priceSetId") Long priceSetId,
@RequestParam(value = "psvId", required = false) Long psvId,
@RequestParam(value = "updateOnly", required = false, defaultValue = "false") boolean updateOnly,
@RequestParam(value = "replaceByProductCountry", required = false, defaultValue = "false") boolean replaceByProductCountry,
@RequestParam(value = "countryCode", required = false) String countryCode)
throws Exception
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
String taskId = priceSetService.submitImportDetailPricesAsync(priceSetId, psvId, UploadFileBatch.collect(files, file),
getUsername(), updateOnly, replaceByProductCountry, countryCode);
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
}
/**
* Preview pull product library (no DB write). For create wizard before finish.
*/
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit') or @ss.hasPermi('price:exclusive:add')")
@PostMapping("/detail/previewPullFromLibrary")
public AjaxResult previewPullFromLibrary()
{
return success(priceSetService.previewPullFromLibrary());
}
/**
* Preview Excel import (no DB write). Optional detailsJson for updateOnly / build-price merge.
* Optional countryCode = single-country dedicated-line Excel (same as product country import).
*/
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit') or @ss.hasPermi('price:exclusive:add')")
@PostMapping("/detail/previewImportPrices")
public AjaxResult previewImportPrices(
@RequestParam(value = "files", required = false) MultipartFile[] files,
@RequestParam(value = "file", required = false) MultipartFile file,
@RequestParam(value = "updateOnly", required = false, defaultValue = "false") boolean updateOnly,
@RequestParam(value = "replaceByProductCountry", required = false, defaultValue = "false") boolean replaceByProductCountry,
@RequestParam(value = "countryCode", required = false) String countryCode,
@RequestParam(value = "detailsJson", required = false) String detailsJson) throws Exception
{
java.util.List<MultipartFile> batch = UploadFileBatch.collect(files, file);
java.util.List<byte[]> bytesList = new java.util.ArrayList<byte[]>();
java.util.List<String> names = new java.util.ArrayList<String>();
for (MultipartFile item : batch)
{
bytesList.add(item.getBytes());
names.add(item.getOriginalFilename());
}
List<PrcPriceSetDetail> existing = null;
if (StringUtils.isNotEmpty(detailsJson))
{
existing = com.alibaba.fastjson2.JSON.parseArray(detailsJson, PrcPriceSetDetail.class);
}
return success(priceSetService.previewImportDetailPricesMany(
bytesList, names, updateOnly, existing, replaceByProductCountry, countryCode, true));
}
/**
* Async pull product library into version details. Returns taskId; poll /save/task/{taskId}.
*/
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote拉取产品", businessType = BusinessType.IMPORT)
@PostMapping("/detail/pullFromLibrary")
public AjaxResult pullFromLibrary(@RequestParam("priceSetId") Long priceSetId,
@RequestParam(value = "psvId", required = false) Long psvId,
@RequestParam(value = "force", required = false, defaultValue = "false") boolean force)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_EXCLUSIVE);
String taskId = priceSetService.submitPullFromLibraryAsync(priceSetId, psvId, force, getUsername());
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
}
/**
* Async batch write of detail surcharge snapshots. Returns taskId; poll /save/task/{taskId}.
*/
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote附加费", businessType = BusinessType.UPDATE)
@PostMapping("/detail/surcharge/async")
public AjaxResult batchSurchargeAsync(@RequestBody List<PrcPriceSetDetail> details)
{
String taskId = priceSetService.submitDetailSurchargeAsync(details);
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("taskId", taskId);
return success(payload);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit') or @ss.hasPermi('price:exclusive:forceEdit')")
@Log(title = "Exclusive quote明细", businessType = BusinessType.DELETE)
@DeleteMapping("/detail/{psdIds}")
public AjaxResult removeDetail(@PathVariable Long[] psdIds)
{
return toAjax(priceSetService.deleteDetailByIds(psdIds));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:list')")
@GetMapping("/customer/list")
public TableDataInfo customerList(PrcCustomerPriceSet customer)
{
startPage();
List<PrcCustomerPriceSet> list = priceSetService.selectCustomerList(customer);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote客户绑定", businessType = BusinessType.INSERT)
@PostMapping("/customer")
public AjaxResult addCustomer(@RequestBody PrcCustomerPriceSet customer)
{
if (customer != null && customer.getPriceSetId() != null)
{
priceSetService.assertSetCategory(customer.getPriceSetId(), PrcPriceSet.CATEGORY_EXCLUSIVE);
}
customer.setCreateBy(getUsername());
return toAjax(priceSetService.insertCustomer(customer));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote客户批量绑定", businessType = BusinessType.INSERT)
@PostMapping("/customer/batch")
public AjaxResult batchAddCustomer(@RequestBody PrcCustomerPriceSetBatch batch)
{
if (batch != null && batch.getPriceSetId() != null)
{
priceSetService.assertSetCategory(batch.getPriceSetId(), PrcPriceSet.CATEGORY_EXCLUSIVE);
}
batch.setCreateBy(getUsername());
batch.setUpdateBy(getUsername());
return success(priceSetService.batchInsertCustomers(batch));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote客户绑定", businessType = BusinessType.UPDATE)
@PutMapping("/customer")
public AjaxResult editCustomer(@RequestBody PrcCustomerPriceSet customer)
{
customer.setUpdateBy(getUsername());
return toAjax(priceSetService.updateCustomer(customer));
}
@PreAuthorize("@ss.hasPermi('price:exclusive:edit')")
@Log(title = "Exclusive quote客户绑定", businessType = BusinessType.DELETE)
@DeleteMapping("/customer/{customerPricesetIds}")
public AjaxResult removeCustomer(@PathVariable Long[] customerPricesetIds)
{
return toAjax(priceSetService.deleteCustomerByIds(customerPricesetIds));
}
}
@@ -55,6 +55,8 @@ public class PriceSetController extends BaseController
@GetMapping("/list")
public TableDataInfo list(PrcPriceSet set)
{
// Ordinary package module: never mix exclusive quotes into this list.
set.setSetCategory(PrcPriceSet.CATEGORY_PACKAGE);
startPage();
List<PrcPriceSet> list = priceSetService.selectPrcPriceSetList(set);
return getDataTable(list);
@@ -64,6 +66,7 @@ public class PriceSetController extends BaseController
@GetMapping("/{priceSetId:[0-9]+}")
public AjaxResult getInfo(@PathVariable Long priceSetId)
{
priceSetService.assertSetCategory(priceSetId, PrcPriceSet.CATEGORY_PACKAGE);
return success(priceSetService.selectPrcPriceSetById(priceSetId));
}
@@ -72,6 +75,11 @@ public class PriceSetController extends BaseController
@PostMapping
public AjaxResult add(@Validated @RequestBody PrcPriceSet set)
{
if (set.getPriceSetId() != null)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_PACKAGE);
}
set.setSetCategory(PrcPriceSet.CATEGORY_PACKAGE);
set.setCreateBy(getUsername());
set.setUpdateBy(getUsername());
String taskId = priceSetService.submitSaveAsync(set);
@@ -98,6 +106,8 @@ public class PriceSetController extends BaseController
@PutMapping
public AjaxResult edit(@Validated @RequestBody PrcPriceSet set)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_PACKAGE);
set.setSetCategory(PrcPriceSet.CATEGORY_PACKAGE);
set.setUpdateBy(getUsername());
return toAjax(priceSetService.updatePrcPriceSet(set));
}
@@ -108,6 +118,7 @@ public class PriceSetController extends BaseController
@PutMapping("/basic")
public AjaxResult editBasic(@RequestBody PrcPriceSet set)
{
priceSetService.assertSetCategory(set.getPriceSetId(), PrcPriceSet.CATEGORY_PACKAGE);
set.setUpdateBy(getUsername());
return toAjax(priceSetService.updateBasicInfo(set));
}