diff --git a/bms-back/AR_ROW_SCOPE.md b/bms-back/AR_ROW_SCOPE.md new file mode 100644 index 00000000..44f95894 --- /dev/null +++ b/bms-back/AR_ROW_SCOPE.md @@ -0,0 +1,38 @@ +# 应收账单行级权限 + +规则独立于 `@DataScope` 和角色管理的 `dataScope`,现有菜单、按钮权限保持不变。 + +| roleKey | 数据范围 | +| --- | --- | +| ORA_6041 / ORA_6163 | 销售员、商务专员:本人负责客户 | +| ORA_6040 | 本部门人员负责客户,不含下级部门 | +| ORA_6042 / ORA_6043 | 财务经理、应收财务:全部账单 | + +超级管理员沿用系统判断。仅参与当前入口功能授权的有效角色合并范围;未知角色、空权限对象默认无数据。财务本期不使用账单 `create_user_id`。应付财务不参与应收账单权限规则。 + +归属链为 `ar_bill.customer_id → ctr_customer.sales_user_id → sys_user.user_id / dept_id`。销售员和商务专员均通过客户的 `sales_user_id` 与当前登录用户 ID 匹配本人客户。客户转交后,历史账单跟随当前归属变化。全量角色可见未关联销售、销售已删除、客户已删除的历史账单;受限角色不放行无有效归属的数据。业务员仅停用但未删除时,其部门经理仍可查看。 + +核心实现位于 `bms-system/src/main/java/com/bms/ar/security` 和 `mapper/ar/ArBillScopeMapper.xml`。内部权限对象作为独立 Mapper 参数传递,不绑定 HTTP 查询对象;后台生成和导出任务继续使用独立的内部读取方法。 + +接入范围包括列表、汇总、列表导出、详情/费用、日志、生成预览及提交、生成任务、导出任务及下载、客户账单入口,以及客户/收款页面的待核销账单、核销记录、核销和反核销。应收筛选及生成客户选项分别使用 `/ar/bill/customer-options`、`/ar/bill/generate/customer-options`。 + +用户编辑、调部门、停用、分配角色,以及角色编辑、停用、删除和授权关系调整,会在事务提交后让受影响的登录会话失效;相关用户需要重新登录。不改变角色配置本身。 + +## 本地验证 + +在 `bms-back` 下执行(PowerShell): + +```powershell +mvn -o -pl bms-admin -am -DskipTests compile +``` + +本次新增的行级权限测试用例及其辅助脚本已按要求删除。 + +在 `bms-front` 下执行 `npm run build:prod` 验证前端构建。 + +## 部署前核实 + +- 本次没有新增数据库字段、权限配置表或迁移 SQL。 +- 目标环境 `ctr_customer.sales_user_id` 必须已经统一为系统用户 ID,不能仍是旧业务员工号。现有迁移文件位于 `sql/customer+supplier/20261028_customer_sales_user_migration.sql`,需要按原有流程确认执行状态,本次不自动执行。 +- 使用真实销售 A/B、经理、财务和商务专员账号检查数据范围与功能授权,特别是生产角色实际拥有的接口权限。 +- 上线前仍需在 MySQL 5.7 环境联调,并检查实际数据的执行计划。 diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java index 10f354c7..16864fb9 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/ar/ArBillController.java @@ -35,6 +35,7 @@ import com.bms.ar.domain.vo.ArBillGenerateRequest; import com.bms.ar.domain.vo.ArBillListExportRow; import com.bms.ar.domain.vo.ArBillQuery; import com.bms.ar.service.IArBillService; +import com.bms.ar.security.ArBillScopeResolver; import com.bms.common.annotation.Log; import com.bms.common.core.controller.BaseController; import com.bms.common.core.domain.AjaxResult; @@ -59,6 +60,24 @@ public class ArBillController extends BaseController { @Autowired private IArBillService billService; + @Autowired + private ArBillScopeResolver billScope; + + /** 应收筛选专用客户选项,与账单使用同一角色规则。 */ + @PreAuthorize("@ss.hasPermi('ar:bill:list')") + @GetMapping("/customer-options") + public TableDataInfo customerOptions(@RequestParam(required = false) String keywords) { + startPage(); + return getDataTable(billScope.selectCustomerOptions(keywords)); + } + + @PreAuthorize("@ss.hasPermi('ar:bill:generate')") + @GetMapping("/generate/customer-options") + public TableDataInfo generateCustomerOptions(@RequestParam(required = false) String keywords) { + startPage(); + return getDataTable(billScope.selectCustomerOptions(keywords)); + } + /** * 查询参数中的日期必须严格按 yyyy-MM-dd 解析,禁止非法日期自动滚动到其他日期。 */ diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/customer/customerinfo/BmsCustomerController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/customer/customerinfo/BmsCustomerController.java index 58c31a03..90a8c546 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/customer/customerinfo/BmsCustomerController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/customer/customerinfo/BmsCustomerController.java @@ -5,6 +5,7 @@ import java.util.List; import com.bms.customer.customerinfo.domain.BmsCustomerAttachment; import com.bms.customer.customerinfo.domain.BmsCustomerCompany; import com.bms.customer.customerinfo.domain.BmsCustomerContact; +import com.bms.customer.customerinfo.vo.UnlinkedSalesCustomerVO; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.beans.factory.annotation.Autowired; @@ -22,6 +23,7 @@ import com.bms.common.core.controller.BaseController; import com.bms.common.core.domain.AjaxResult; import com.bms.common.enums.BusinessType; import com.bms.customer.customerinfo.domain.BmsCustomer; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; import com.bms.customer.customerinfo.service.IBmsCustomerService; import com.bms.common.utils.poi.ExcelUtil; import com.bms.common.core.page.TableDataInfo; @@ -51,6 +53,32 @@ public class BmsCustomerController extends BaseController return getDataTable(list); } + /** 查询未关联业务员的客户列表 */ + @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:list')") + @GetMapping("/unlinked-sales-user/list") + public TableDataInfo unlinkedSalesUserList() + { + startPage(); + BmsCustomer query = new BmsCustomer(); + List list = bmsCustomerService.selectUnlinkedSalesUserCustomerList(query); + return getDataTable(list); + } + + /** + * 客户下拉选项。 + * 只返回客户ID、客户编码、客户名称,供各页面下拉框使用。 + * 查询参数 keywords 按客户名称、客户编码、对外代码模糊匹配,多行之间为或者关系。 + * 分页参数与原下拉一致,避免一次查出全部客户。 + */ +// @PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:list')") + @GetMapping("/optionselect") + public TableDataInfo optionselect(BmsCustomer query) + { + startPage(); + List list = bmsCustomerService.selectCustomerOptions(query); + return getDataTable(list); + } + /** * 导出客户信息列表 */ diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/masterdata/ServiceChannelController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/masterdata/ServiceChannelController.java index cbdd55f2..96165e9d 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/masterdata/ServiceChannelController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/masterdata/ServiceChannelController.java @@ -1,17 +1,29 @@ package com.bms.web.controller.masterdata; import java.util.List; +import jakarta.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +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.RestController; +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.poi.ExcelUtil; import com.bms.masterdata.domain.ServiceChannel; import com.bms.masterdata.service.IServiceChannelService; /** - * 服务渠道(老系统镜像 srv_service_channel) + * 渠道管理(srv_service_channel) + * 下拉选项仍走 /optionselect,登录即可,供供应商绑定渠道使用。 * * @author bms * @date 2026-10-12 @@ -23,6 +35,32 @@ public class ServiceChannelController extends BaseController @Autowired private IServiceChannelService serviceChannelService; + /** + * 分页查询渠道列表。 + * 渠道编码、渠道名称、服务商编码、服务商名称、目的港/目的地区域、发货人名称均可检索,名称类条件为模糊匹配。 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:list')") + @GetMapping("/list") + public TableDataInfo list(ServiceChannel query) + { + startPage(); + List list = serviceChannelService.selectServiceChannelList(query); + return getDataTable(list); + } + + /** + * 导出渠道列表,筛选条件与列表一致。 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:export')") + @Log(title = "渠道管理", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ServiceChannel query) + { + List list = serviceChannelService.selectServiceChannelList(query); + ExcelUtil util = new ExcelUtil(ServiceChannel.class); + util.exportExcel(response, list, "渠道数据"); + } + /** * 服务渠道下拉选项(非分页)。 * 供供应商绑定渠道等场景选择渠道;不做权限控制(仍需登录)。 @@ -33,4 +71,63 @@ public class ServiceChannelController extends BaseController List list = serviceChannelService.selectServiceChannelList(query); return success(list); } + + /** + * 查询渠道详情 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:query')") + @GetMapping("/{id}") + public AjaxResult getInfo(@PathVariable String id) + { + return success(serviceChannelService.selectServiceChannelById(id)); + } + + /** + * 新增渠道 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:add')") + @Log(title = "渠道管理", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ServiceChannel channel) + { + String username = getUsername(); + channel.setCreateName(username); + channel.setModifier(username); + return toAjax(serviceChannelService.insertServiceChannel(channel)); + } + + /** + * 修改渠道 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')") + @Log(title = "渠道管理", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ServiceChannel channel) + { + channel.setModifier(getUsername()); + return toAjax(serviceChannelService.updateServiceChannel(channel)); + } + + /** + * 启用或停用渠道 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:edit')") + @Log(title = "渠道管理", businessType = BusinessType.UPDATE) + @PutMapping("/changeStatus") + public AjaxResult changeStatus(@RequestBody ServiceChannel channel) + { + channel.setModifier(getUsername()); + return toAjax(serviceChannelService.updateServiceChannelStatus(channel)); + } + + /** + * 删除渠道。已被产品渠道或供应商引用时不允许删除。 + */ + @PreAuthorize("@ss.hasPermi('data:serviceChannel:remove')") + @Log(title = "渠道管理", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable String[] ids) + { + return toAjax(serviceChannelService.deleteServiceChannelByIds(ids)); + } } diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java index f19ac1b5..de7c9e6c 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/PriceSetController.java @@ -227,6 +227,14 @@ public class PriceSetController extends BaseController 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:set:list')") + @GetMapping("/detail/byVersion") + public AjaxResult detailByVersion(@RequestParam("psvId") Long psvId) + { + return success(priceSetService.selectDetailListByVersion(psvId)); + } + /** * 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */ diff --git a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java index b022c9c4..40564b26 100644 --- a/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java +++ b/bms-back/bms-admin/src/main/java/com/bms/web/controller/price/ProductController.java @@ -63,13 +63,13 @@ public class ProductController extends BaseController } /** - * 产品下拉选项(非分页)。 - * 供计费列表、客户绑定等场景选择产品;不做权限控制(仍需登录)。 + * Product dropdown (non-paged). Slim query, no list-page status refresh. + * Used by price-set / billing / customer bind; login required, no extra perm. */ @GetMapping("/optionselect") public AjaxResult optionselect(BmsProduct product) { - List list = productService.selectBmsProductList(product); + List list = productService.selectBmsProductOptions(product); return success(list); } diff --git a/bms-back/bms-admin/src/main/resources/i18n/messages.properties b/bms-back/bms-admin/src/main/resources/i18n/messages.properties index fe2ceafc..ce897e9c 100644 --- a/bms-back/bms-admin/src/main/resources/i18n/messages.properties +++ b/bms-back/bms-admin/src/main/resources/i18n/messages.properties @@ -122,6 +122,7 @@ price.product.import.sheetNotFound=未找到「产品目录」sheet,请上传 price.product.import.noData=产品目录无有效数据行 price.product.import.catalogHeaderMissing=「产品目录」未找到表头「对接代码」,请在标题行下补齐表头(对接代码、产品名称、时效、走货属性、国家等) price.product.import.countryCatalogHeaderMissing=「产品目录」未找到表头「产品名称」或「产品ID」,请确认是否为单国专线成本价表格式 +price.product.import.singleCountryAsMulti=当前选择的是「全部导入(多国家价表)」,但上传的文件更像单国专线成本价表(价表无「国家」列)。请改用「按国家导入」,并选择目的国家后再上传。 price.product.import.regionEmpty=region 无可用国家数据,请先同步/维护国家表后再导入 price.product.import.partialFail=导入完成但存在失败项:新增 {0},跳过 {1};失败明细:{2} price.product.import.effTooEarly=产品{0}({1})导入生效时间{2}早于该产品上一版生效时间{3},不允许导入 diff --git a/bms-back/bms-common/src/main/java/com/bms/common/utils/PermissionContext.java b/bms-back/bms-common/src/main/java/com/bms/common/utils/PermissionContext.java new file mode 100644 index 00000000..802079cf --- /dev/null +++ b/bms-back/bms-common/src/main/java/com/bms/common/utils/PermissionContext.java @@ -0,0 +1,21 @@ +package com.bms.common.utils; + +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; + +/** 由服务端功能鉴权写入的请求上下文,不读取请求参数。 */ +public final class PermissionContext { + private static final String ATTRIBUTE = "PERMISSION_CONTEXT"; + + private PermissionContext() {} + + public static void set(String permission) { + RequestContextHolder.currentRequestAttributes().setAttribute(ATTRIBUTE, permission, RequestAttributes.SCOPE_REQUEST); + } + + public static String get() { + RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); + Object value = attributes == null ? null : attributes.getAttribute(ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); + return value instanceof String ? (String) value : null; + } +} diff --git a/bms-back/bms-framework/src/main/java/com/bms/framework/aspectj/AuthorizationSessionAspect.java b/bms-back/bms-framework/src/main/java/com/bms/framework/aspectj/AuthorizationSessionAspect.java new file mode 100644 index 00000000..76ec5f63 --- /dev/null +++ b/bms-back/bms-framework/src/main/java/com/bms/framework/aspectj/AuthorizationSessionAspect.java @@ -0,0 +1,78 @@ +package com.bms.framework.aspectj; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import com.bms.common.core.domain.entity.SysRole; +import com.bms.common.core.domain.entity.SysUser; +import com.bms.framework.web.service.TokenService; +import com.bms.system.domain.SysUserRole; + +/** 授权关系修改提交后,让旧登录态失效;不参与业务 SQL 数据范围计算。 */ +@Aspect +@Component +@Order(1) +public class AuthorizationSessionAspect { + private final TokenService tokenService; + + public AuthorizationSessionAspect(TokenService tokenService) { + this.tokenService = tokenService; + } + + @AfterReturning(pointcut = "execution(* com.bms.system.service.impl.SysUserServiceImpl.updateUser(..))" + + " || execution(* com.bms.system.service.impl.SysUserServiceImpl.updateUserStatus(..))" + + " || execution(* com.bms.system.service.impl.SysUserServiceImpl.insertUserAuth(..))" + + " || execution(* com.bms.system.service.impl.SysUserServiceImpl.deleteUserBy*(..))", returning = "result") + public void userChanged(JoinPoint point, Object result) { + if (result instanceof Number && ((Number) result).intValue() <= 0) return; + Object target = point.getArgs()[0]; + Set users = new HashSet<>(); + if (target instanceof SysUser) users.add(((SysUser) target).getUserId()); + else if (target instanceof Long[]) users.addAll(Arrays.asList((Long[]) target)); + else if (target instanceof Long) users.add((Long) target); + invalidate(users, Set.of()); + } + + @AfterReturning(pointcut = "execution(* com.bms.system.service.impl.SysRoleServiceImpl.updateRole(..))" + + " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.updateRoleStatus(..))" + + " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.deleteRoleBy*(..))" + + " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.deleteAuthUser*(..))" + + " || execution(* com.bms.system.service.impl.SysRoleServiceImpl.insertAuthUsers(..))", returning = "result") + public void roleChanged(JoinPoint point, Object result) { + if (result instanceof Number && ((Number) result).intValue() <= 0) return; + Object target = point.getArgs()[0]; + Set users = new HashSet<>(); + Set roles = new HashSet<>(); + if (target instanceof SysUserRole) users.add(((SysUserRole) target).getUserId()); + else if (point.getArgs().length > 1 && point.getArgs()[1] instanceof Long[]) + users.addAll(Arrays.asList((Long[]) point.getArgs()[1])); + else if (target instanceof SysRole) roles.add(((SysRole) target).getRoleId()); + else if (target instanceof Long[]) roles.addAll(Arrays.asList((Long[]) target)); + else if (target instanceof Long) roles.add((Long) target); + invalidate(users, roles); + } + + private void invalidate(Set users, Set roles) { + users.remove(null); + Set roleIds = new HashSet<>(roles); + roleIds.remove(null); + Set userIds = Set.copyOf(users); + if (userIds.isEmpty() && roleIds.isEmpty()) return; + Runnable action = () -> tokenService.evictAuthorizationSessions(userIds, roleIds); + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { action.run(); } + }); + } else { + action.run(); + } + } +} diff --git a/bms-back/bms-framework/src/main/java/com/bms/framework/security/context/PermissionContextHolder.java b/bms-back/bms-framework/src/main/java/com/bms/framework/security/context/PermissionContextHolder.java index 61a55172..ec5f7a0f 100644 --- a/bms-back/bms-framework/src/main/java/com/bms/framework/security/context/PermissionContextHolder.java +++ b/bms-back/bms-framework/src/main/java/com/bms/framework/security/context/PermissionContextHolder.java @@ -1,8 +1,6 @@ package com.bms.framework.security.context; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; -import com.bms.common.core.text.Convert; +import com.bms.common.utils.PermissionContext; /** * 权限信息 @@ -11,17 +9,13 @@ import com.bms.common.core.text.Convert; */ public class PermissionContextHolder { - private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT"; - public static void setContext(String permission) { - RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission, - RequestAttributes.SCOPE_REQUEST); + PermissionContext.set(permission); } public static String getContext() { - return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES, - RequestAttributes.SCOPE_REQUEST)); + return PermissionContext.get(); } } diff --git a/bms-back/bms-framework/src/main/java/com/bms/framework/web/service/TokenService.java b/bms-back/bms-framework/src/main/java/com/bms/framework/web/service/TokenService.java index 0c3cbc39..0bac6c99 100644 --- a/bms-back/bms-framework/src/main/java/com/bms/framework/web/service/TokenService.java +++ b/bms-back/bms-framework/src/main/java/com/bms/framework/web/service/TokenService.java @@ -3,6 +3,7 @@ package com.bms.framework.web.service; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -231,6 +232,22 @@ public class TokenService return CacheConstants.LOGIN_TOKEN_KEY + uuid; } + /** 授权或部门变更后失效受影响会话,避免缓存中的旧角色继续扩大业务范围。 */ + public void evictAuthorizationSessions(Set userIds, Set roleIds) + { + Collection keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*"); + if (keys == null) return; + for (String key : keys) + { + LoginUser user = redisCache.getCacheObject(key); + if (user == null || user.getUser() == null) continue; + boolean affected = userIds.contains(user.getUserId()) + || (user.getUser().getRoles() != null && user.getUser().getRoles().stream() + .anyMatch(role -> role != null && roleIds.contains(role.getRoleId()))); + if (affected) redisCache.deleteObject(key); + } + } + /** * 角色权限变更后,刷新所有持有该角色的在线用户权限 * diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBalanceWriteoffMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBalanceWriteoffMapper.java index 08842035..3f97cca2 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBalanceWriteoffMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBalanceWriteoffMapper.java @@ -1,6 +1,8 @@ package com.bms.ar.mapper; import java.util.List; +import com.bms.ar.security.ArBillRowScope; + import org.apache.ibatis.annotations.Param; import com.bms.ar.domain.ArBalanceWriteoff; @@ -33,5 +35,5 @@ public interface ArBalanceWriteoffMapper @Param("effectiveStatus") String effectiveStatus); /** 查询核销记录列表(关联账单名称/客户名称) */ - List selectWriteoffList(ArBalanceWriteoff query); + List selectWriteoffList(@Param("query") ArBalanceWriteoff query, @Param("scope") ArBillRowScope scope); } diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailFeeMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailFeeMapper.java index 7b0a0909..5c75df9c 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailFeeMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailFeeMapper.java @@ -1,11 +1,14 @@ package com.bms.ar.mapper; import java.util.List; +import com.bms.ar.security.ArBillRowScope; import org.apache.ibatis.annotations.Param; import com.bms.ar.domain.ArBillDetailFee; public interface ArBillDetailFeeMapper { + List selectByBillIdAndDetailIdScoped(@Param("arBillId") Long arBillId, @Param("detailId") Long detailId, @Param("scope") ArBillRowScope scope); + List selectByDetailId(Long detailId); List selectByBillIdAndDetailId(@Param("arBillId") Long arBillId, diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailMapper.java index 6defde18..15ccdfa9 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillDetailMapper.java @@ -1,12 +1,16 @@ package com.bms.ar.mapper; import java.util.List; +import com.bms.ar.security.ArBillRowScope; + import java.util.Map; import org.apache.ibatis.annotations.Param; import com.bms.ar.domain.ArBillDetail; public interface ArBillDetailMapper { + List selectByBillIdScoped(@Param("arBillId") Long arBillId, @Param("scope") ArBillRowScope scope); + List selectByBillId(Long arBillId); List selectByBillIdAndSourceIds(@Param("arBillId") Long arBillId, diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillGenerateTaskMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillGenerateTaskMapper.java index 5e0d9af4..b0c398ea 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillGenerateTaskMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillGenerateTaskMapper.java @@ -10,6 +10,9 @@ import com.bms.ar.domain.ArBillGenerateTask; * 应收账单异步生成任务 Mapper。 */ public interface ArBillGenerateTaskMapper { + List selectActiveByCreateByScoped(@Param("createBy") String createBy, + @Param("scope") com.bms.ar.security.ArBillRowScope scope); + ArBillGenerateTask selectById(Long taskId); ArBillGenerateTask selectByRequestToken(String requestToken); diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillLogMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillLogMapper.java index d98f5087..01c569bf 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillLogMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillLogMapper.java @@ -1,12 +1,14 @@ package com.bms.ar.mapper; import java.util.List; +import com.bms.ar.security.ArBillRowScope; + import org.apache.ibatis.annotations.Param; import com.bms.ar.domain.ArBillLog; public interface ArBillLogMapper { - List selectList(ArBillLog query); + List selectList(@Param("query") ArBillLog query, @Param("scope") ArBillRowScope scope); ArBillLog selectSuccessByRequestId(@Param("requestId") String requestId, @Param("objectType") String objectType, diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillMapper.java index 2b0b16d3..2c1bd595 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillMapper.java @@ -3,6 +3,7 @@ package com.bms.ar.mapper; import java.math.BigDecimal; import java.util.Date; import java.util.List; +import com.bms.ar.security.ArBillRowScope; import org.apache.ibatis.annotations.Param; import com.bms.ar.domain.ArBill; @@ -10,12 +11,14 @@ import com.bms.ar.domain.vo.ArBillQuery; import com.bms.ar.domain.vo.ArBillSummary; public interface ArBillMapper { - List selectArBillList(ArBillQuery query); + List selectArBillList(@Param("query") ArBillQuery query, @Param("scope") ArBillRowScope scope); - ArBillSummary selectArBillSummary(ArBillQuery query); + ArBillSummary selectArBillSummary(@Param("query") ArBillQuery query, @Param("scope") ArBillRowScope scope); ArBill selectArBillById(Long arBillId); + ArBill selectArBillByIdScoped(@Param("arBillId") Long arBillId, @Param("scope") ArBillRowScope scope); + ArBill selectArBillByBillNo(String billNo); ArBill selectGeneratingByCustomerPeriod(@Param("customerId") Long customerId, @@ -29,7 +32,7 @@ public interface ArBillMapper { /** * 查询客户可核销账单(已确认/部分核销),按账单日期升序,供余额核销选择 */ - List selectUnsettledByCustomer(@Param("customerId") Long customerId); + List selectUnsettledByCustomer(@Param("customerId") Long customerId, @Param("scope") ArBillRowScope scope); int insertArBill(ArBill bill); diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillScopeMapper.java b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillScopeMapper.java new file mode 100644 index 00000000..15cc7490 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/ar/mapper/ArBillScopeMapper.java @@ -0,0 +1,17 @@ +package com.bms.ar.mapper; + +import java.util.List; +import org.apache.ibatis.annotations.Param; +import com.bms.ar.security.ArBillRowScope; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; + +public interface ArBillScopeMapper { + int countCustomerSourceBills(@Param("customerId") Long customerId, @Param("sourceIds") List sourceIds); + + int countAccessibleBill(@Param("arBillId") Long arBillId, @Param("scope") ArBillRowScope scope); + + BmsCustomerOption selectAccessibleCustomer(@Param("customerId") Long customerId, @Param("scope") ArBillRowScope scope); + + List selectCustomerOptions(@Param("keywords") List keywords, + @Param("scope") ArBillRowScope scope); +} diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRoleKeys.java b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRoleKeys.java new file mode 100644 index 00000000..850d1427 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRoleKeys.java @@ -0,0 +1,23 @@ +package com.bms.ar.security; + +import java.util.Set; + +/** 应收业务范围,与角色管理的 dataScope 配置无关。 */ +public final class ArBillRoleKeys { + public static final String SALES = "ORA_6041"; + public static final String BUSINESS_SPECIALIST = "ORA_6163"; + public static final String SALES_MANAGER = "ORA_6040"; + /** 销售员、商务专员:本人负责客户的账单。 */ + public static final Set SELF_DATA_ROLES = Set.of(SALES, BUSINESS_SPECIALIST); + /** 财务经理、应收财务;仍须具备对应接口的功能权限。 */ + public static final Set ALL_DATA_ROLES = Set.of("ORA_6042", "ORA_6043"); + + static { + if (SELF_DATA_ROLES.contains(SALES_MANAGER) || ALL_DATA_ROLES.contains(SALES_MANAGER) + || SELF_DATA_ROLES.stream().anyMatch(ALL_DATA_ROLES::contains)) { + throw new IllegalStateException("应收数据权限角色映射冲突"); + } + } + + private ArBillRoleKeys() {} +} diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRowScope.java b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRowScope.java new file mode 100644 index 00000000..38eec00b --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillRowScope.java @@ -0,0 +1,24 @@ +package com.bms.ar.security; + +/** 仅由后端构造,不能绑定到 HTTP 查询对象。 */ +public final class ArBillRowScope { + private final boolean all; + private final boolean self; + private final boolean department; + private final Long userId; + private final Long deptId; + + ArBillRowScope(boolean all, boolean self, boolean department, Long userId, Long deptId) { + this.all = all; + this.self = self && userId != null && userId > 0; + this.department = department && deptId != null && deptId > 0; + this.userId = userId; + this.deptId = deptId; + } + + public boolean isAll() { return all; } + public boolean isSelf() { return self; } + public boolean isDepartment() { return department; } + public Long getUserId() { return userId; } + public Long getDeptId() { return deptId; } +} diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillScopeResolver.java b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillScopeResolver.java new file mode 100644 index 00000000..6bf5c4ab --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/ar/security/ArBillScopeResolver.java @@ -0,0 +1,101 @@ +package com.bms.ar.security; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.function.Supplier; +import com.github.pagehelper.Page; +import com.github.pagehelper.PageHelper; +import org.springframework.stereotype.Component; +import com.bms.ar.mapper.ArBillScopeMapper; +import com.bms.common.constant.Constants; +import com.bms.common.core.domain.entity.SysRole; +import com.bms.common.core.domain.entity.SysUser; +import com.bms.common.core.domain.model.LoginUser; +import com.bms.common.exception.ServiceException; +import com.bms.common.utils.PermissionContext; +import com.bms.common.utils.SecurityUtils; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; + +@Component +public class ArBillScopeResolver { + private final ArBillScopeMapper mapper; + + public ArBillScopeResolver(ArBillScopeMapper mapper) { + this.mapper = mapper; + } + + /** 只读取登录态;功能上下文由 @ss.hasPermi 写入,缺失时不授权。 */ + public ArBillRowScope resolve() { + return resolve(SecurityUtils.getLoginUser(), PermissionContext.get()); + } + + public ArBillRowScope resolve(LoginUser actor, String permission) { + if (actor == null || actor.getUser() == null || actor.getUserId() == null) { + throw new ServiceException("登录状态无效,请重新登录", 401); + } + SysUser user = actor.getUser(); + if (!"0".equals(user.getStatus()) || !"0".equals(user.getDelFlag())) { + return new ArBillRowScope(false, false, false, actor.getUserId(), actor.getDeptId()); + } + if (user.isAdmin()) { + return new ArBillRowScope(true, false, false, actor.getUserId(), actor.getDeptId()); + } + boolean all = false; + boolean self = false; + boolean department = false; + if (permission != null && !permission.isBlank() && user.getRoles() != null) { + for (SysRole role : user.getRoles()) { + if (role == null || !"0".equals(role.getStatus()) || !permits(role.getPermissions(), permission)) continue; + String key = role.getRoleKey(); + all |= ArBillRoleKeys.ALL_DATA_ROLES.contains(key == null ? "" : key); + self |= ArBillRoleKeys.SELF_DATA_ROLES.contains(key == null ? "" : key); + department |= ArBillRoleKeys.SALES_MANAGER.equals(key); + } + } + return new ArBillRowScope(all, self, department, actor.getUserId(), actor.getDeptId()); + } + + private boolean permits(Set permissions, String required) { + return permissions != null && (permissions.contains(Constants.ALL_PERMISSION) + || Arrays.stream(required.split(Constants.PERMISSION_DELIMITER)).map(String::trim).anyMatch(permissions::contains)); + } + + public void requireBillAccessible(Long arBillId) { + ArBillRowScope scope = resolve(); + if (arBillId == null || withoutPagination(() -> mapper.countAccessibleBill(arBillId, scope)) == 0) { + throw new ServiceException("账单不存在或无权访问"); + } + } + + public BmsCustomerOption requireCustomerAccessible(Long customerId) { + ArBillRowScope scope = resolve(); + BmsCustomerOption customer = customerId == null ? null + : withoutPagination(() -> mapper.selectAccessibleCustomer(customerId, scope)); + if (customer == null) throw new ServiceException("客户不存在或无权访问"); + return customer; + } + + public List selectCustomerOptions(String keywords) { + List values = keywords == null ? List.of() + : Arrays.stream(keywords.split("\\R")).map(String::trim).filter(s -> !s.isEmpty()).distinct().toList(); + return mapper.selectCustomerOptions(values, resolve()); + } + + public void requireCustomerSourceBills(Long customerId, List sourceIds) { + if (!sourceIds.isEmpty() && withoutPagination(() -> mapper.countCustomerSourceBills(customerId, sourceIds)) != sourceIds.size()) { + throw new ServiceException("所选订单不存在或不属于当前客户"); + } + } + + /** 资源预校验不能消耗 Controller 已设置的分页,最终业务查询仍使用原分页对象。 */ + private T withoutPagination(Supplier query) { + Page page = PageHelper.getLocalPage(); + PageHelper.clearPage(); + try { + return query.get(); + } finally { + if (page != null) PageHelper.setLocalPage(page); + } + } +} diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBalanceWriteoffServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBalanceWriteoffServiceImpl.java index 00e91757..44738f62 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBalanceWriteoffServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBalanceWriteoffServiceImpl.java @@ -23,6 +23,7 @@ import com.bms.ar.enums.ArLogOperationType; import com.bms.ar.enums.ArLogResult; import com.bms.ar.mapper.ArBalanceWriteoffMapper; import com.bms.ar.mapper.ArBillMapper; +import com.bms.ar.security.ArBillScopeResolver; import com.bms.ar.service.IArBalanceWriteoffService; import com.bms.ar.service.IArBillLogService; import com.bms.common.exception.ServiceException; @@ -46,6 +47,8 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService { @Autowired private ArBillMapper billMapper; + @Autowired + private ArBillScopeResolver billScope; @Autowired private ArBalanceWriteoffMapper writeoffMapper; @@ -67,7 +70,7 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService { if (customerId == null) { return List.of(); } - return billMapper.selectUnsettledByCustomer(customerId); + return billMapper.selectUnsettledByCustomer(customerId, billScope.resolve()); } /** @@ -75,7 +78,7 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService { */ @Override public List selectWriteoffList(ArBalanceWriteoff query) { - return writeoffMapper.selectWriteoffList(query); + return writeoffMapper.selectWriteoffList(query, billScope.resolve()); } /** @@ -103,6 +106,7 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService { if (bill == null) { throw new ServiceException("应收账单不存在"); } + billScope.requireBillAccessible(bill.getArBillId()); ArBillStatus status = ArBillStatus.of(bill.getStatus()); if (status == null || !status.canWriteOff()) { throw new ServiceException("当前账单状态不允许核销:" + (status == null ? bill.getStatus() : status.getLabel())); @@ -170,6 +174,7 @@ public class ArBalanceWriteoffServiceImpl implements IArBalanceWriteoffService { if (writeoff == null) { throw new ServiceException("核销记录不存在"); } + billScope.requireBillAccessible(writeoff.getArBillId()); if (!ArBalanceWriteoffStatus.EFFECTIVE.getCode().equals(writeoff.getStatus())) { throw new ServiceException("只有有效状态的核销记录可以反核销"); } diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillLogServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillLogServiceImpl.java index b98e5b38..4231daa2 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillLogServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillLogServiceImpl.java @@ -12,6 +12,7 @@ import com.bms.ar.enums.ArLogOperationSource; import com.bms.ar.enums.ArLogOperationType; import com.bms.ar.enums.ArLogResult; import com.bms.ar.mapper.ArBillLogMapper; +import com.bms.ar.security.ArBillScopeResolver; import com.bms.ar.service.IArBillLogService; import com.bms.common.utils.uuid.IdUtils; @@ -19,10 +20,12 @@ import com.bms.common.utils.uuid.IdUtils; public class ArBillLogServiceImpl implements IArBillLogService { @Autowired private ArBillLogMapper logMapper; + @Autowired + private ArBillScopeResolver billScope; @Override public List selectLogList(ArBillLog query) { - return logMapper.selectList(query); + return logMapper.selectList(query, billScope.resolve()); } @Override diff --git a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java index 16d18791..890d047c 100644 --- a/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/ar/service/impl/ArBillServiceImpl.java @@ -70,6 +70,8 @@ import com.bms.ar.mapper.ArBillDetailMapper; import com.bms.ar.mapper.ArBillExportMapper; import com.bms.ar.mapper.ArBillLogMapper; import com.bms.ar.mapper.ArBillMapper; +import com.bms.ar.security.ArBillScopeResolver; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; import com.bms.ar.mapper.ArBillGenerateTaskMapper; import com.bms.ar.mapper.ArBankAccountMapper; import com.bms.ar.mapper.ArExportTemplateMapper; @@ -182,6 +184,8 @@ public class ArBillServiceImpl implements IArBillService { @Autowired private ArBillMapper billMapper; @Autowired + private ArBillScopeResolver billScope; + @Autowired private ArBillGenerateTaskMapper generateTaskMapper; @Autowired private ArBankAccountMapper bankAccountMapper; @@ -214,7 +218,8 @@ public class ArBillServiceImpl implements IArBillService { @Override public List selectArBillList(ArBillQuery query) { long startedAt = System.nanoTime(); - List bills = billMapper.selectArBillList(query); + query = query == null ? new ArBillQuery() : query; + List bills = billMapper.selectArBillList(query, billScope.resolve()); for (ArBill bill : bills) { bill.setBankAccountNo(maskAccount(bill.getBankAccountNo())); } @@ -229,7 +234,7 @@ public class ArBillServiceImpl implements IArBillService { */ @Override public ArBillSummary selectArBillSummary(ArBillQuery query) { - return billMapper.selectArBillSummary(query); + return billMapper.selectArBillSummary(query == null ? new ArBillQuery() : query, billScope.resolve()); } /** @@ -238,9 +243,9 @@ public class ArBillServiceImpl implements IArBillService { @Override public ArBill selectArBillById(Long arBillId) { long startedAt = System.nanoTime(); - ArBill bill = billMapper.selectArBillById(arBillId); + ArBill bill = billMapper.selectArBillByIdScoped(arBillId, billScope.resolve()); if (bill == null) { - throw new ServiceException("应收账单不存在"); + throw new ServiceException("账单不存在或无权访问"); } bill.setBankAccountNo(maskAccount(bill.getBankAccountNo())); bill.setExports(exportMapper.selectByBillId(arBillId)); @@ -256,7 +261,7 @@ public class ArBillServiceImpl implements IArBillService { @Override public List selectArBillDetails(Long arBillId) { long startedAt = System.nanoTime(); - List details = detailMapper.selectByBillId(arBillId); + List details = detailMapper.selectByBillIdScoped(arBillId, billScope.resolve()); log.debug("应收账单明细查询完成,arBillId={}, resultCount={}, costMs={}", arBillId, details.size(), elapsedMillis(startedAt)); return details; @@ -268,7 +273,7 @@ public class ArBillServiceImpl implements IArBillService { @Override public List selectArBillDetailFees(Long arBillId, Long detailId) { long startedAt = System.nanoTime(); - List fees = detailFeeMapper.selectByBillIdAndDetailId(arBillId, detailId); + List fees = detailFeeMapper.selectByBillIdAndDetailIdScoped(arBillId, detailId, billScope.resolve()); log.debug("应收账单费用明细查询完成,arBillId={}, detailId={}, resultCount={}, costMs={}", arBillId, detailId, fees.size(), elapsedMillis(startedAt)); return fees; @@ -308,6 +313,8 @@ public class ArBillServiceImpl implements IArBillService { public List previewBill(ArBillGenerateQuery query) { long startedAt = System.nanoTime(); validatePreviewQuery(query); + BmsCustomerOption customer = billScope.requireCustomerAccessible(query.getCustomerId()); + query.setCustomerCode(customer.getCustomerCode()); List orderIdentifiers = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()); List excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); List result = sourceBillMapper.selectPrcOrderBillByCustomerPeriod(query.getCustomerId(), @@ -336,6 +343,8 @@ public class ArBillServiceImpl implements IArBillService { public BigDecimal sumPreviewBill(ArBillGenerateQuery query) { long startedAt = System.nanoTime(); validatePreviewQuery(query); + BmsCustomerOption customer = billScope.requireCustomerAccessible(query.getCustomerId()); + query.setCustomerCode(customer.getCustomerCode()); List orderIdentifiers = normalizeOrderIdentifiers(query.getOrderOrTrackingNo()); List excludeOrderIdentifiers = normalizeOrderIdentifiers(query.getExcludeOrderOrTrackingNo()); BigDecimal total = nvl(sourceBillMapper.sumPrcOrderBillIncomeByCustomerPeriod(query.getCustomerId(), @@ -359,8 +368,12 @@ public class ArBillServiceImpl implements IArBillService { long startedAt = System.nanoTime(); Long createUserId = SecurityUtils.getUserId(); validatePeriod(request); + BmsCustomerOption customer = billScope.requireCustomerAccessible(request.getCustomerId()); + request.setCustomerCode(customer.getCustomerCode()); + request.setCustomerName(customer.getCustomerName()); ArBillGenerateTask existed = generateTaskMapper.selectByRequestToken(requestId); if (existed != null) { + billScope.requireBillAccessible(existed.getArBillId()); log.info("应收账单生成请求命中幂等记录,operator={}, requestId={}, taskId={}, status={}, costMs={}", safeLogValue(operator), safeLogValue(requestId), existed.getTaskId(), existed.getStatus(), elapsedMillis(startedAt)); @@ -401,6 +414,7 @@ public class ArBillServiceImpl implements IArBillService { validateOrderIdentifierParameterCount( orderIdentifierCount, allMatched ? excludedSourceBillIds.size() : sourceBillIds.size()); + billScope.requireCustomerSourceBills(request.getCustomerId(), allMatched ? excludedSourceBillIds : sourceBillIds); request.setSelectionMode(selectionMode); String currency = StringUtils.isEmpty(request.getCurrency()) ? "CNY" : request.getCurrency().trim(); @@ -478,8 +492,9 @@ public class ArBillServiceImpl implements IArBillService { long startedAt = System.nanoTime(); ArBillGenerateTask task = generateTaskMapper.selectById(taskId); if (task == null) { - throw new ServiceException("账单生成任务不存在"); + throw new ServiceException("账单不存在或无权访问"); } + billScope.requireBillAccessible(task.getArBillId()); log.debug("应收账单生成任务状态查询,taskId={}, status={}, processedCount={}, totalCount={}, costMs={}", taskId, task.getStatus(), task.getProcessedCount(), task.getTotalCount(), elapsedMillis(startedAt)); return task; @@ -491,7 +506,7 @@ public class ArBillServiceImpl implements IArBillService { @Override public List selectActiveGenerateTasks(String operator) { long startedAt = System.nanoTime(); - List tasks = generateTaskMapper.selectActiveByCreateBy(operator); + List tasks = generateTaskMapper.selectActiveByCreateByScoped(operator, billScope.resolve()); log.debug("当前用户应收账单生成任务查询,operator={}, taskCount={}, costMs={}", safeLogValue(operator), tasks.size(), elapsedMillis(startedAt)); return tasks; @@ -504,7 +519,9 @@ public class ArBillServiceImpl implements IArBillService { @Transactional(rollbackFor = Exception.class) public ArBillGenerateTask cancelGenerateTask(Long taskId, String operator, String requestId) { long startedAt = System.nanoTime(); - ArBillGenerateTask task = selectGenerateTask(taskId); + ArBillGenerateTask task = generateTaskMapper.selectById(taskId); + if (task == null) throw new ServiceException("账单不存在或无权访问"); + billScope.requireBillAccessible(task.getArBillId()); if (!operator.equals(task.getCreateBy())) { throw new ServiceException("只能取消自己创建的账单生成任务"); } @@ -533,7 +550,9 @@ public class ArBillServiceImpl implements IArBillService { @Transactional(rollbackFor = Exception.class) public ArBillGenerateTask retryGenerateTask(Long taskId, String operator, String requestId) { long startedAt = System.nanoTime(); - ArBillGenerateTask task = selectGenerateTask(taskId); + ArBillGenerateTask task = generateTaskMapper.selectById(taskId); + if (task == null) throw new ServiceException("账单不存在或无权访问"); + billScope.requireBillAccessible(task.getArBillId()); if (!operator.equals(task.getCreateBy())) { throw new ServiceException("只能重新生成自己创建的账单任务"); } @@ -923,6 +942,7 @@ public class ArBillServiceImpl implements IArBillService { public ArBill confirmBill(Long arBillId, ArBillActionRequest request, String operator, String requestId) { long startedAt = System.nanoTime(); ArBill bill = billMapper.selectArBillByIdForUpdate(arBillId); + billScope.requireBillAccessible(arBillId); if (bill == null) { throw failure(arBillId, ArLogObjectType.BILL, String.valueOf(arBillId), ArLogOperationType.CONFIRM, null, "应收账单不存在", operator, requestId); @@ -972,6 +992,7 @@ public class ArBillServiceImpl implements IArBillService { null, "作废必须填写原因", operator, requestId); } ArBill bill = billMapper.selectArBillByIdForUpdate(arBillId); + billScope.requireBillAccessible(arBillId); if (bill == null) { throw failure(arBillId, ArLogObjectType.BILL, String.valueOf(arBillId), ArLogOperationType.VOID, null, "应收账单不存在", operator, requestId); @@ -1011,11 +1032,13 @@ public class ArBillServiceImpl implements IArBillService { public ArBillExport exportBill(Long arBillId, String operator, String requestId) { long startedAt = System.nanoTime(); Long exportUserId = SecurityUtils.getUserId(); + billScope.requireBillAccessible(arBillId); ArBillLog previous = logMapper.selectSuccessByRequestId(requestId, ArLogObjectType.EXPORT.getCode(), ArLogResult.SUCCESS.getCode()); if (previous != null && isNumber(previous.getObjectId())) { ArBillExport previousExport = exportMapper.selectById(Long.valueOf(previous.getObjectId())); if (previousExport != null) { + billScope.requireBillAccessible(previousExport.getArBillId()); log.info("应收账单导出请求命中幂等记录,operator={}, requestId={}, arBillId={}, exportId={}, status={}, costMs={}", safeLogValue(operator), safeLogValue(requestId), arBillId, previousExport.getExportId(), previousExport.getExportStatus(), elapsedMillis(startedAt)); @@ -1084,9 +1107,8 @@ public class ArBillServiceImpl implements IArBillService { public ArBillExport selectExport(Long exportId) { long startedAt = System.nanoTime(); ArBillExport export = exportMapper.selectById(exportId); - if (export == null) { - throw new ServiceException("导出任务不存在"); - } + if (export == null) throw new ServiceException("账单不存在或无权访问"); + billScope.requireBillAccessible(export.getArBillId()); log.debug("应收账单导出任务状态查询,exportId={}, status={}, costMs={}", exportId, export.getExportStatus(), elapsedMillis(startedAt)); return export; @@ -1167,6 +1189,7 @@ public class ArBillServiceImpl implements IArBillService { @Override public List selectExports(Long arBillId) { long startedAt = System.nanoTime(); + billScope.requireBillAccessible(arBillId); List exports = exportMapper.selectByBillId(arBillId); log.debug("应收账单导出记录查询,arBillId={}, exportCount={}, costMs={}", arBillId, exports.size(), elapsedMillis(startedAt)); @@ -1177,7 +1200,11 @@ public class ArBillServiceImpl implements IArBillService { public void downloadExport(Long exportId, HttpServletResponse response) throws Exception { long startedAt = System.nanoTime(); ArBillExport export = exportMapper.selectById(exportId); - if (export == null || !ArExportStatus.SUCCESS.getCode().equals(export.getExportStatus()) || StringUtils.isEmpty(export.getStorageKey())) { + if (export == null) { + throw new ServiceException("账单不存在或无权访问"); + } + billScope.requireBillAccessible(export.getArBillId()); + if (!ArExportStatus.SUCCESS.getCode().equals(export.getExportStatus()) || StringUtils.isEmpty(export.getStorageKey())) { throw new ServiceException("导出文件不存在或尚未生成成功"); } String resource = export.getStorageKey(); diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomerOption.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomerOption.java new file mode 100644 index 00000000..bedd63f0 --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/domain/BmsCustomerOption.java @@ -0,0 +1,22 @@ +package com.bms.customer.customerinfo.domain; + +import lombok.Data; + +/** + * 客户下拉选项。 + * 只携带下拉展示和回填需要的字段,不返回额度、账期等客户档案内容。 + * + * @author bms + */ +@Data +public class BmsCustomerOption +{ + /** 客户ID。收款、账单等已有下拉按主键选中,需一并返回 */ + private Long customerId; + + /** 客户编码 */ + private String customerCode; + + /** 客户名称 */ + private String customerName; +} diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/mapper/BmsCustomerMapper.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/mapper/BmsCustomerMapper.java index 540b5206..5907cdac 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/mapper/BmsCustomerMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/mapper/BmsCustomerMapper.java @@ -1,10 +1,9 @@ package com.bms.customer.customerinfo.mapper; import java.util.List; -import com.bms.customer.customerinfo.domain.BmsCustomer; -import com.bms.customer.customerinfo.domain.BmsCustomerAttachment; -import com.bms.customer.customerinfo.domain.BmsCustomerCompany; -import com.bms.customer.customerinfo.domain.BmsCustomerContact; + +import com.bms.customer.customerinfo.domain.*; +import com.bms.customer.customerinfo.vo.UnlinkedSalesCustomerVO; import io.lettuce.core.dynamic.annotation.Param; /** @@ -34,6 +33,18 @@ public interface BmsCustomerMapper */ public List selectBmsCustomerList(BmsCustomer bmsCustomer); + /** + * 查询客户下拉选项。 + * 按客户名称、客户编码、对外代码模糊匹配,只返回下拉所需字段。 + * + * @param query 下拉查询条件 + * @return 客户下拉选项 + */ + public List selectCustomerOptions(BmsCustomer query); + + /** 独立分页查询未关联业务员的客户,仅按 sales_user_id 为空筛选。 */ + public List selectUnlinkedSalesUserCustomerList(BmsCustomer query); + /** 校验业务员用户ID仍对应未删除的系统用户。 */ public int countValidSalesUserId(@org.apache.ibatis.annotations.Param("salesUserId") String salesUserId); diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/IBmsCustomerService.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/IBmsCustomerService.java index b6476ae3..6b1c42bd 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/IBmsCustomerService.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/IBmsCustomerService.java @@ -2,10 +2,12 @@ package com.bms.customer.customerinfo.service; import java.util.List; import com.bms.customer.customerinfo.domain.BmsCustomer; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; import com.bms.customer.customerinfo.domain.BmsCustomerAttachment; import com.bms.customer.customerinfo.domain.BmsCustomerCompany; import com.bms.customer.customerinfo.domain.BmsCustomerContact; import com.bms.customer.customerinfo.domain.BmsCustomerLog; +import com.bms.customer.customerinfo.vo.UnlinkedSalesCustomerVO; /** * 客户主Service接口 @@ -39,6 +41,18 @@ public interface IBmsCustomerService */ public List selectBmsCustomerList(BmsCustomer bmsCustomer); + /** 独立查询未关联业务员的客户。 */ + public List selectUnlinkedSalesUserCustomerList(BmsCustomer query); + + /** + * 查询客户下拉选项。 + * 只返回客户ID、客户编码、客户名称;keywords 按客户名称、客户编码、对外代码模糊查询。 + * + * @param query 下拉查询条件 + * @return 客户下拉选项 + */ + public List selectCustomerOptions(BmsCustomer query); + /** * 查询客户附件列表 * diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerPriceSetServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerPriceSetServiceImpl.java index 022d5376..834d556c 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerPriceSetServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerPriceSetServiceImpl.java @@ -73,14 +73,6 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi { throw new ServiceException("仅生效中的套餐允许绑定,当前套餐状态不可用"); } - if (bind.getPrBegindate() == null) - { - throw new ServiceException("绑定生效日期不能为空"); - } - if (bind.getPrEnddate() != null && bind.getPrBegindate().after(bind.getPrEnddate())) - { - throw new ServiceException("失效日期不能早于生效日期"); - } if (bind.getBindPriority() == null || bind.getBindPriority() < 1) { bind.setBindPriority(1); @@ -105,6 +97,15 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi if (existing != null) { bind.setCustomerPricesetId(existing.getCustomerPricesetId()); + // 弹框已不再采集生效/失效日期,未传入时保留库中原值 + if (bind.getPrBegindate() == null) + { + bind.setPrBegindate(existing.getPrBegindate()); + } + if (bind.getPrEnddate() == null) + { + bind.setPrEnddate(existing.getPrEnddate()); + } rows = bindMapper.updateBind(bind); } else @@ -144,14 +145,6 @@ public class BmsCustomerPriceSetServiceImpl implements IBmsCustomerPriceSetServi { throw new ServiceException("仅生效中的套餐允许绑定,当前套餐状态不可用"); } - if (req.getPrBegindate() == null) - { - throw new ServiceException("绑定生效日期不能为空"); - } - if (req.getPrEnddate() != null && req.getPrBegindate().after(req.getPrEnddate())) - { - throw new ServiceException("失效日期不能早于生效日期"); - } Integer priority = (req.getBindPriority() == null || req.getBindPriority() < 1) ? 1 : req.getBindPriority(); boolean overwrite = Boolean.TRUE.equals(req.getOverwriteExisting()); diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerServiceImpl.java index 63ff757e..ec2b7a8e 100644 --- a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/service/impl/BmsCustomerServiceImpl.java @@ -17,7 +17,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.bms.customer.customerinfo.mapper.BmsCustomerMapper; import com.bms.customer.customerinfo.domain.BmsCustomer; +import com.bms.customer.customerinfo.domain.BmsCustomerOption; import com.bms.customer.customerinfo.domain.BmsCustomerLog; +import com.bms.customer.customerinfo.vo.UnlinkedSalesCustomerVO; import com.bms.customer.customerinfo.service.IBmsCustomerLogService; import com.bms.customer.customerinfo.service.IBmsCustomerService; import com.bms.customer.customermoney.service.ICustomerMoneyService; @@ -89,6 +91,24 @@ public class BmsCustomerServiceImpl implements IBmsCustomerService return bmsCustomerMapper.selectBmsCustomerList(bmsCustomer); } + /** 查询未关联业务员客户,保留客户业务员维度的数据范围。 */ + @Override + @DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id") + public List selectUnlinkedSalesUserCustomerList(BmsCustomer query) + { + return bmsCustomerMapper.selectUnlinkedSalesUserCustomerList(query); + } + + /** + * 客户下拉选项。数据权限与客户列表一致,只查下拉需要的字段。 + */ + @Override + @DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id") + public List selectCustomerOptions(BmsCustomer query) + { + return bmsCustomerMapper.selectCustomerOptions(query); + } + //查询附件子表数据 @Override public List selectBmsCustomerAttachmentList(BmsCustomerAttachment bmsCustomerAttachment) { diff --git a/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/vo/UnlinkedSalesCustomerVO.java b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/vo/UnlinkedSalesCustomerVO.java new file mode 100644 index 00000000..9bfc324b --- /dev/null +++ b/bms-back/bms-system/src/main/java/com/bms/customer/customerinfo/vo/UnlinkedSalesCustomerVO.java @@ -0,0 +1,16 @@ +package com.bms.customer.customerinfo.vo; + +import lombok.Data; + +/** 未关联业务员客户弹窗专用列表响应。 */ +@Data +public class UnlinkedSalesCustomerVO +{ + private Long customerId; + private String customerCode; + private String customerName; + private String customerCodeDw; + private String customerType; + private String isEnable; + private String sourceSalesCode; +} diff --git a/bms-back/bms-system/src/main/java/com/bms/masterdata/domain/ServiceChannel.java b/bms-back/bms-system/src/main/java/com/bms/masterdata/domain/ServiceChannel.java index 0796cef2..34e01a9d 100644 --- a/bms-back/bms-system/src/main/java/com/bms/masterdata/domain/ServiceChannel.java +++ b/bms-back/bms-system/src/main/java/com/bms/masterdata/domain/ServiceChannel.java @@ -2,6 +2,7 @@ package com.bms.masterdata.domain; import java.util.Date; import com.fasterxml.jackson.annotation.JsonFormat; +import com.bms.common.annotation.Excel; import lombok.Data; /** @@ -17,53 +18,98 @@ public class ServiceChannel private String id; /** 渠道编码 */ + @Excel(name = "渠道编码") private String channelCode; /** 渠道名称 */ + @Excel(name = "渠道名称") private String channelName; /** 所属服务商编码 */ + @Excel(name = "服务商编码") private String serviceCode; /** 所属服务商名称 */ + @Excel(name = "服务商名称") private String serviceName; /** 是否启用(1启用 0停用) */ + @Excel(name = "是否启用", readConverterExp = "1=启用,0=停用") private String blOpen; /** 是否支持多票(1是 0否) */ + @Excel(name = "是否多票", readConverterExp = "1=是,0=否") private String blMultiple; + @Excel(name = "货物类型") private String cargoType; + + @Excel(name = "付款方式") private String payType; + + @Excel(name = "发货人名称") private String shipperName; + + @Excel(name = "发货人ID") private String shipperId; + + @Excel(name = "轨迹查询类型") private String queryType; + + @Excel(name = "轨迹编码") private String trajectoryCode; + + @Excel(name = "末端服务商") private String finalServiceName; + + @Excel(name = "目的港/目的地区域") private String desPort; /** 重量类型 */ + @Excel(name = "重量类型") private String weightType; /** 体积除数(抛货系数) */ + @Excel(name = "抛货系数") private Long dimDivisor; + @Excel(name = "计重规则") private String weightRule; + + @Excel(name = "发货类型") private String shipmentType; + + @Excel(name = "数据来源") private String dataFrom; + + @Excel(name = "备注") private String remarks; + @Excel(name = "创建人") private String createName; + private String createManCode; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Excel(name = "创建时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") private Date createDate; + + @Excel(name = "修改人") private String modifier; + private String modifierCode; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Excel(name = "修改时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") private Date modifyDate; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date gmtCreate; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date gmtModified; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + @Excel(name = "同步时间", width = 20, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date syncTime; } diff --git a/bms-back/bms-system/src/main/java/com/bms/masterdata/mapper/ServiceChannelMapper.java b/bms-back/bms-system/src/main/java/com/bms/masterdata/mapper/ServiceChannelMapper.java index bf9f949a..304dec9f 100644 --- a/bms-back/bms-system/src/main/java/com/bms/masterdata/mapper/ServiceChannelMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/masterdata/mapper/ServiceChannelMapper.java @@ -4,7 +4,7 @@ import java.util.List; import com.bms.masterdata.domain.ServiceChannel; /** - * 服务渠道镜像表查询(MASTER 数据源) + * 服务渠道 srv_service_channel * * @author bms * @date 2026-10-12 @@ -12,7 +12,48 @@ import com.bms.masterdata.domain.ServiceChannel; public interface ServiceChannelMapper { /** - * 查询服务渠道列表(支持渠道编码/名称/服务商编码/启用状态过滤,非分页) + * 查询服务渠道列表。 + * 渠道名称、服务商名称、目的港/目的地区域、发货人名称为模糊匹配;编码同样按包含匹配,便于列表检索。 */ List selectServiceChannelList(ServiceChannel query); + + /** + * 按主键查询渠道 + */ + ServiceChannel selectServiceChannelById(String id); + + /** + * 按渠道编码精确查询(唯一性校验) + */ + ServiceChannel selectServiceChannelByCode(String channelCode); + + /** + * 产品渠道关系中引用该渠道编码的数量 + */ + int countProductChannelByCode(String channelCode); + + /** + * 供应商绑定中引用该渠道编码的数量 + */ + int countSupplierByChannelCode(String channelCode); + + /** + * 新增渠道 + */ + int insertServiceChannel(ServiceChannel channel); + + /** + * 修改渠道 + */ + int updateServiceChannel(ServiceChannel channel); + + /** + * 只更新启用状态 + */ + int updateServiceChannelStatus(ServiceChannel channel); + + /** + * 批量删除渠道 + */ + int deleteServiceChannelByIds(String[] ids); } diff --git a/bms-back/bms-system/src/main/java/com/bms/masterdata/service/IServiceChannelService.java b/bms-back/bms-system/src/main/java/com/bms/masterdata/service/IServiceChannelService.java index d94253bf..47dcc7fa 100644 --- a/bms-back/bms-system/src/main/java/com/bms/masterdata/service/IServiceChannelService.java +++ b/bms-back/bms-system/src/main/java/com/bms/masterdata/service/IServiceChannelService.java @@ -4,7 +4,7 @@ import java.util.List; import com.bms.masterdata.domain.ServiceChannel; /** - * 服务渠道镜像 服务层 + * 服务渠道 服务层 * * @author bms * @date 2026-10-12 @@ -12,7 +12,32 @@ import com.bms.masterdata.domain.ServiceChannel; public interface IServiceChannelService { /** - * 查询服务渠道列表(非分页,供供应商绑定渠道等下拉选择场景) + * 查询服务渠道列表(分页由调用方 startPage 控制;下拉场景不传分页) */ List selectServiceChannelList(ServiceChannel query); + + /** + * 查询渠道详情 + */ + ServiceChannel selectServiceChannelById(String id); + + /** + * 新增渠道 + */ + int insertServiceChannel(ServiceChannel channel); + + /** + * 修改渠道 + */ + int updateServiceChannel(ServiceChannel channel); + + /** + * 启用或停用渠道(只改 bl_open) + */ + int updateServiceChannelStatus(ServiceChannel channel); + + /** + * 批量删除渠道。已被产品渠道或供应商引用时拒绝删除。 + */ + int deleteServiceChannelByIds(String[] ids); } diff --git a/bms-back/bms-system/src/main/java/com/bms/masterdata/service/impl/ServiceChannelServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/masterdata/service/impl/ServiceChannelServiceImpl.java index 201cff5b..abd9b2c4 100644 --- a/bms-back/bms-system/src/main/java/com/bms/masterdata/service/impl/ServiceChannelServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/masterdata/service/impl/ServiceChannelServiceImpl.java @@ -3,12 +3,15 @@ package com.bms.masterdata.service.impl; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.bms.common.exception.ServiceException; +import com.bms.common.utils.StringUtils; +import com.bms.common.utils.uuid.IdUtils; import com.bms.masterdata.domain.ServiceChannel; import com.bms.masterdata.mapper.ServiceChannelMapper; import com.bms.masterdata.service.IServiceChannelService; /** - * 服务渠道镜像 服务实现 + * 服务渠道 服务实现 * * @author bms * @date 2026-10-12 @@ -24,4 +27,169 @@ public class ServiceChannelServiceImpl implements IServiceChannelService { return serviceChannelMapper.selectServiceChannelList(query); } + + @Override + public ServiceChannel selectServiceChannelById(String id) + { + return serviceChannelMapper.selectServiceChannelById(id); + } + + @Override + public int insertServiceChannel(ServiceChannel channel) + { + prepare(channel, true); + assertCodeUnique(channel); + channel.setId(IdUtils.fastSimpleUUID()); + if (StringUtils.isEmpty(channel.getDataFrom())) + { + channel.setDataFrom("BMS"); + } + return serviceChannelMapper.insertServiceChannel(channel); + } + + @Override + public int updateServiceChannel(ServiceChannel channel) + { + if (channel == null || StringUtils.isEmpty(channel.getId())) + { + throw new ServiceException("渠道ID不能为空"); + } + ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(channel.getId()); + if (existing == null) + { + throw new ServiceException("渠道不存在或已被删除"); + } + prepare(channel, false); + assertCodeUnique(channel); + if (!StringUtils.equals(existing.getChannelCode(), channel.getChannelCode()) + && countUsage(existing.getChannelCode()) > 0) + { + throw new ServiceException("渠道「" + existing.getChannelName() + "」已被产品渠道或供应商引用,不能修改渠道编码"); + } + return serviceChannelMapper.updateServiceChannel(channel); + } + + @Override + public int updateServiceChannelStatus(ServiceChannel channel) + { + if (channel == null || StringUtils.isEmpty(channel.getId())) + { + throw new ServiceException("渠道ID不能为空"); + } + if (!"0".equals(channel.getBlOpen()) && !"1".equals(channel.getBlOpen())) + { + throw new ServiceException("启用状态只能是启用或停用"); + } + ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(channel.getId()); + if (existing == null) + { + throw new ServiceException("渠道不存在或已被删除"); + } + return serviceChannelMapper.updateServiceChannelStatus(channel); + } + + @Override + public int deleteServiceChannelByIds(String[] ids) + { + if (ids == null || ids.length == 0) + { + throw new ServiceException("请选择要删除的渠道"); + } + for (String id : ids) + { + if (StringUtils.isEmpty(id)) + { + continue; + } + ServiceChannel existing = serviceChannelMapper.selectServiceChannelById(id); + if (existing == null) + { + continue; + } + if (countUsage(existing.getChannelCode()) > 0) + { + throw new ServiceException("渠道「" + existing.getChannelName() + "」已被产品渠道或供应商引用,不能删除,请改为停用"); + } + } + return serviceChannelMapper.deleteServiceChannelByIds(ids); + } + + private void prepare(ServiceChannel channel, boolean creating) + { + if (channel == null) + { + throw new ServiceException("渠道信息不能为空"); + } + channel.setChannelCode(StringUtils.trim(channel.getChannelCode())); + channel.setChannelName(StringUtils.trim(channel.getChannelName())); + channel.setServiceCode(trimToNull(channel.getServiceCode())); + channel.setServiceName(trimToNull(channel.getServiceName())); + channel.setShipperName(trimToNull(channel.getShipperName())); + channel.setDesPort(trimToNull(channel.getDesPort())); + if (StringUtils.isEmpty(channel.getChannelCode())) + { + throw new ServiceException("渠道编码不能为空"); + } + if (channel.getChannelCode().length() > 64) + { + throw new ServiceException("渠道编码不能超过64个字符"); + } + if (StringUtils.isEmpty(channel.getChannelName())) + { + throw new ServiceException("渠道名称不能为空"); + } + if (channel.getChannelName().length() > 200) + { + throw new ServiceException("渠道名称不能超过200个字符"); + } + if (StringUtils.isEmpty(channel.getBlOpen())) + { + if (creating) + { + channel.setBlOpen("1"); + } + else + { + throw new ServiceException("请选择启用状态"); + } + } + if (!"0".equals(channel.getBlOpen()) && !"1".equals(channel.getBlOpen())) + { + throw new ServiceException("启用状态只能是启用或停用"); + } + if (StringUtils.isNotEmpty(channel.getBlMultiple()) + && !"0".equals(channel.getBlMultiple()) && !"1".equals(channel.getBlMultiple())) + { + throw new ServiceException("是否多票只能是是或否"); + } + if (channel.getDimDivisor() != null && channel.getDimDivisor() < 0) + { + throw new ServiceException("抛货系数不能为负数"); + } + } + + private void assertCodeUnique(ServiceChannel channel) + { + ServiceChannel same = serviceChannelMapper.selectServiceChannelByCode(channel.getChannelCode()); + if (same != null && !StringUtils.equals(same.getId(), channel.getId())) + { + throw new ServiceException("渠道编码「" + channel.getChannelCode() + "」已存在"); + } + } + + private int countUsage(String channelCode) + { + if (StringUtils.isEmpty(channelCode)) + { + return 0; + } + return serviceChannelMapper.countProductChannelByCode(channelCode) + + serviceChannelMapper.countSupplierByChannelCode(channelCode); + } + + private String trimToNull(String value) + { + String text = StringUtils.trim(value); + return StringUtils.isEmpty(text) ? null : text; + } } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetVersion.java b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetVersion.java index 96255825..befb7652 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetVersion.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/domain/PrcPriceSetVersion.java @@ -29,11 +29,10 @@ public class PrcPriceSetVersion extends BaseEntity /** 0 draft / 3 pending / 1 active / 2 expired */ private String status; /** - * Create-price mode for this version: - * PULL = from product library, - * IMPORT = Excel with prior version preload, - * IMPORT_FRESH = Excel without prior version data. - * Column: price_build_mode + * Create-price mode for this version (column: price_build_mode). + * SALES: PULL = product library; IMPORT = Excel + prior version; IMPORT_FRESH = Excel blank. + * PRODUCT/REDLINE: IMPORT = copy from effect version; IMPORT_FRESH = rebuild (Excel). + * Legacy catalog: COPY → IMPORT, old IMPORT → IMPORT_FRESH (see migrate SQL). */ private String priceBuildMode; /** 0 normal / 1 soft-deleted */ diff --git a/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java b/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java index 9e0a79d9..18dc6d7e 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/mapper/BmsProductMapper.java @@ -30,6 +30,9 @@ public interface BmsProductMapper public List selectBmsProductList(BmsProduct product); + /** Dropdown options: slim columns, no country/surcharge count subqueries */ + public List selectBmsProductOptions(BmsProduct product); + public int insertBmsProduct(BmsProduct product); public int updateBmsProduct(BmsProduct product); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java index 003ceb4a..53c547b7 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IBmsProductService.java @@ -19,6 +19,9 @@ public interface IBmsProductService public List selectBmsProductList(BmsProduct product); + /** Product dropdown options (no status refresh, no count subqueries). */ + public List selectBmsProductOptions(BmsProduct product); + public int insertBmsProduct(BmsProduct product); public int updateBmsProduct(BmsProduct product); diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java index 08a19764..698793f6 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/IPrcPriceSetService.java @@ -71,6 +71,11 @@ public interface IPrcPriceSetService */ public List selectDetailListByProduct(Long psvId, String productCode); + /** + * Load all detail rows for a version (no pagination). For batch prefetch vs N byProduct calls. + */ + public List selectDetailListByVersion(Long psvId); + /** * 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 列表。 * 返回 { products: [{code,name}], countries: [{code,name}], zones: [{code,name}] } diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java index 65174558..dfc53670 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/BmsProductServiceImpl.java @@ -129,8 +129,7 @@ public class BmsProductServiceImpl implements IBmsProductService @Override public List selectBmsProductList(BmsProduct product) { - productMapper.refreshStatusByDates(); - countryMapper.refreshStatusByDates(); + // Status refresh is done on activate / scheduled task; skip UPDATE on every list read. if (product != null) { product.setStatus(normalizeStatusCode(product.getStatus())); @@ -139,6 +138,17 @@ public class BmsProductServiceImpl implements IBmsProductService return productMapper.selectBmsProductList(product); } + @Override + public List selectBmsProductOptions(BmsProduct product) + { + if (product != null) + { + product.setStatus(normalizeStatusCode(product.getStatus())); + product.setEffectStatus(normalizeStatusCode(product.getEffectStatus())); + } + return productMapper.selectBmsProductOptions(product); + } + @Override public int insertBmsProduct(BmsProduct product) { @@ -378,6 +388,7 @@ public class BmsProductServiceImpl implements IBmsProductService { throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound")); } + assertNotSingleCountryQuoteForMultiImport(workbook); List products = parseCatalog(catalog); if (products.isEmpty()) @@ -678,6 +689,7 @@ public class BmsProductServiceImpl implements IBmsProductService { throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound")); } + assertNotSingleCountryQuoteForMultiImport(workbook); List products = dedupeCatalogProducts(parseCatalog(catalog)); if (products.isEmpty()) { @@ -763,6 +775,7 @@ public class BmsProductServiceImpl implements IBmsProductService } if (out.isEmpty()) { + assertNotSingleCountryQuoteForMultiImport(workbook); throw new ServiceException(MessageUtils.message("price.set.import.noPriceRows")); } QuoteWorkbook parsed = new QuoteWorkbook(); @@ -778,6 +791,80 @@ public class BmsProductServiceImpl implements IBmsProductService private Map> byCode; } + /** + * Multi-country import expects price sheets with a "country" column. + * Single-country dedicated-line sheets use product-name + weight blocks instead. + */ + private void assertNotSingleCountryQuoteForMultiImport(Workbook workbook) + { + if (looksLikeSingleCountryQuote(workbook)) + { + throw new ServiceException(MessageUtils.message("price.product.import.singleCountryAsMulti")); + } + } + + /** Detect single-country cost-sheet layout (no country column on price sheets). */ + private boolean looksLikeSingleCountryQuote(Workbook workbook) + { + if (workbook == null) + { + return false; + } + boolean sawCountryCol = false; + boolean sawCountryPriceBlock = false; + for (int i = 0; i < workbook.getNumberOfSheets(); i++) + { + String sheetName = workbook.getSheetName(i); + if (shouldSkipCountryPriceSheet(sheetName)) + { + continue; + } + Sheet sheet = workbook.getSheetAt(i); + if (sheet == null) + { + continue; + } + if (findHeaderCell(sheet, "\u56fd\u5bb6") != null) + { + sawCountryCol = true; + break; + } + int[] nameHeader = findHeaderCell(sheet, "\u4ea7\u54c1\u540d\u79f0"); + if (nameHeader == null) + { + continue; + } + Row head = sheet.getRow(nameHeader[0]); + if (head == null) + { + continue; + } + if (findColByHeader(head, "\u91cd\u91cf", 0) >= 0) + { + sawCountryPriceBlock = true; + } + } + if (sawCountryCol) + { + return false; + } + if (sawCountryPriceBlock) + { + return true; + } + Sheet catalog = workbook.getSheet(CATALOG_SHEET); + if (catalog == null) + { + return false; + } + if (findHeaderCell(catalog, "\u5bf9\u63a5\u4ee3\u7801") != null) + { + return false; + } + return findHeaderCell(catalog, "\u4ea7\u54c1\u540d\u79f0") != null + || findHeaderCell(catalog, "\u4ea7\u54c1ID") != null; + } + @Override public Map> parseCountryQuoteExcelByProduct(byte[] bytes, String filename, String countryCode) throws Exception diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java index f4e1b740..59760922 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/impl/PrcPriceSetServiceImpl.java @@ -881,6 +881,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService return selectDetailList(q); } + @Override + public List selectDetailListByVersion(Long psvId) + { + if (psvId == null) + { + return new ArrayList(); + } + PrcPriceSetDetail q = new PrcPriceSetDetail(); + q.setPsvId(psvId); + return selectDetailList(q); + } + @Override public Map selectDetailOptions(Long psvId) { diff --git a/bms-back/bms-system/src/main/java/com/bms/price/service/support/CatalogVersionSupport.java b/bms-back/bms-system/src/main/java/com/bms/price/service/support/CatalogVersionSupport.java index f85cffdf..ad65c958 100644 --- a/bms-back/bms-system/src/main/java/com/bms/price/service/support/CatalogVersionSupport.java +++ b/bms-back/bms-system/src/main/java/com/bms/price/service/support/CatalogVersionSupport.java @@ -102,7 +102,8 @@ public class CatalogVersionSupport nv.setVersionNo("V" + next); nv.setEffectiveTime(effectiveTime); nv.setStatus(STATUS_DRAFT); - nv.setPriceBuildMode("IMPORT"); + // IMPORT = inherit effect version; IMPORT_FRESH = empty rebuild (Excel) + nv.setPriceBuildMode(copyFromLatest ? "IMPORT" : "IMPORT_FRESH"); nv.setCreateBy("system"); versionMapper.insertPrcPriceSetVersion(nv); @@ -122,7 +123,11 @@ public class CatalogVersionSupport return nv; } - /** Activate draft: set EFFECT, chain expire on previous EFFECT versions of same type. */ + /** + * Activate draft/pending catalog version. + * IMPORT_FRESH (align sales): may start inside a prior window; forbid equal to any other + * version's effective/expire of the same price_type; then chain expire times and sync children. + */ public void activateVersion(Long psvId, Date effectiveTime) { PrcPriceSetVersion ver = versionMapper.selectPrcPriceSetVersionById(psvId); @@ -140,39 +145,165 @@ public class CatalogVersionSupport { throw new ServiceException("请选择生效时间"); } - Date prevEff = findPrevEffectiveTime(ver); - if (prevEff != null && eff.before(prevEff)) + boolean importFresh = "IMPORT_FRESH".equalsIgnoreCase(StringUtils.trim(ver.getPriceBuildMode())); + if (importFresh) { - throw new ServiceException("生效时间不能早于上一版本"); + validateImportFreshActivateTime(ver, eff); } - - boolean future = eff.after(new Date()); - if (!future) + else { - PrcPriceSetVersion q = new PrcPriceSetVersion(); - q.setPriceType(ver.getPriceType()); - q.setStatus(STATUS_EFFECT); - List prevList = versionMapper.selectPrcPriceSetVersionList(q); - if (prevList != null) + Date prevEff = findPrevEffectiveTime(ver); + if (prevEff != null && eff.before(prevEff)) { - for (PrcPriceSetVersion prev : prevList) - { - if (prev.getPsvId().equals(psvId)) - { - continue; - } - prev.setExpireTime(eff); - prev.setStatus(STATUS_EXPIRED); - versionMapper.updatePrcPriceSetVersion(prev); - } + throw new ServiceException("生效时间不能早于上一版本"); } } ver.setEffectiveTime(eff); ver.setExpireTime(null); - ver.setStatus(future ? STATUS_PENDING : STATUS_EFFECT); versionMapper.updatePrcPriceSetVersion(ver); - refreshCatalogStatuses(ver.getPriceType()); + // Chain B.expire=A.eff, A.expire=next/B.oldExpire; refresh status + product/detail effect + chainAndRefreshCatalogStatuses(ver.getPriceType()); + } + + /** + * IMPORT_FRESH: may be earlier than prev-by-seq; must not equal any other version's eff/exp + * within the same PRODUCT/REDLINE type. + */ + private void validateImportFreshActivateTime(PrcPriceSetVersion version, Date effectiveTime) + { + if (version == null || effectiveTime == null || StringUtils.isEmpty(version.getPriceType())) + { + return; + } + PrcPriceSetVersion q = new PrcPriceSetVersion(); + q.setPriceType(version.getPriceType()); + List list = versionMapper.selectPrcPriceSetVersionList(q); + if (list == null || list.isEmpty()) + { + return; + } + for (PrcPriceSetVersion v : list) + { + if (v == null) + { + continue; + } + if (version.getPsvId() != null && version.getPsvId().equals(v.getPsvId())) + { + continue; + } + if (sameTime(v.getEffectiveTime(), effectiveTime) || sameTime(v.getExpireTime(), effectiveTime)) + { + throw new ServiceException("生效时间不能与已有版本的生效时间或失效时间相同"); + } + } + } + + /** + * Sort timed versions by effective_time, chain expire_time = next start, then set status + * and sync product/detail effect fields (same idea as sales refreshVersionStatus). + */ + private void chainAndRefreshCatalogStatuses(String priceType) + { + assertCatalogType(priceType); + PrcPriceSetVersion q = new PrcPriceSetVersion(); + q.setPriceType(priceType); + List versions = versionMapper.selectPrcPriceSetVersionList(q); + if (versions == null || versions.isEmpty()) + { + return; + } + versions.sort((a, b) -> { + Date ta = a.getEffectiveTime(); + Date tb = b.getEffectiveTime(); + if (ta == null && tb == null) + { + return Integer.compare(nullToZero(a.getVersionSeq()), nullToZero(b.getVersionSeq())); + } + if (ta == null) + { + return 1; + } + if (tb == null) + { + return -1; + } + int c = ta.compareTo(tb); + if (c != 0) + { + return c; + } + return Integer.compare(nullToZero(a.getVersionSeq()), nullToZero(b.getVersionSeq())); + }); + Date now = new Date(); + Long effectPsvId = null; + for (int i = 0; i < versions.size(); i++) + { + PrcPriceSetVersion v = versions.get(i); + Date nextStart = null; + for (int j = i + 1; j < versions.size(); j++) + { + Date t = versions.get(j).getEffectiveTime(); + if (t != null) + { + nextStart = t; + break; + } + } + v.setExpireTime(nextStart); + if (v.getEffectiveTime() == null) + { + v.setStatus(STATUS_DRAFT); + continue; + } + if (v.getEffectiveTime().getTime() > now.getTime()) + { + v.setStatus(STATUS_PENDING); + continue; + } + if (nextStart != null && nextStart.getTime() <= now.getTime()) + { + v.setStatus(STATUS_EXPIRED); + continue; + } + v.setStatus(STATUS_EFFECT); + effectPsvId = v.getPsvId(); + } + if (effectPsvId != null) + { + for (PrcPriceSetVersion v : versions) + { + if (STATUS_EFFECT.equals(v.getStatus()) + && v.getPsvId() != null + && !v.getPsvId().equals(effectPsvId)) + { + v.setStatus(STATUS_EXPIRED); + } + } + } + for (PrcPriceSetVersion v : versions) + { + PrcPriceSetVersion db = versionMapper.selectPrcPriceSetVersionById(v.getPsvId()); + if (db == null) + { + continue; + } + boolean statusChanged = !String.valueOf(v.getStatus()).equals(String.valueOf(db.getStatus())); + boolean expireChanged = !sameTime(v.getExpireTime(), db.getExpireTime()); + boolean effChanged = !sameTime(v.getEffectiveTime(), db.getEffectiveTime()); + if (statusChanged || expireChanged || effChanged) + { + versionMapper.updatePrcPriceSetVersion(v); + } + } + productMapper.syncEffectByPriceType(priceType); + detailMapper.syncEffectByPriceType(priceType); + } + + private static int nullToZero(Integer v) + { + return v == null ? 0 : v.intValue(); } public List listVersions(String priceType, String status) @@ -345,14 +476,16 @@ public class CatalogVersionSupport /** * Prepare draft for catalog price create page. - * copyFromLatest=true: copy from current EFFECT version when draft is empty. - * copyFromLatest=false: empty draft (Excel import / rebuild). + * copyFromLatest=true → priceBuildMode=IMPORT: copy from current EFFECT version when draft is empty. + * copyFromLatest=false → priceBuildMode=IMPORT_FRESH: empty draft (Excel import / rebuild). + * Legacy values COPY/IMPORT are migrated by SQL to IMPORT/IMPORT_FRESH. */ public PrcPriceSetVersion prepareDraftVersion(String priceType, boolean copyFromLatest) { assertCatalogType(priceType); List drafts = listVersions(priceType, STATUS_DRAFT); PrcPriceSetVersion draft; + String mode = copyFromLatest ? "IMPORT" : "IMPORT_FRESH"; if (drafts.isEmpty()) { if (copyFromLatest) @@ -364,7 +497,7 @@ public class CatalogVersionSupport } } draft = ensureDraftVersion(priceType, null, copyFromLatest); - draft.setPriceBuildMode(copyFromLatest ? "COPY" : "IMPORT"); + draft.setPriceBuildMode(mode); versionMapper.updatePrcPriceSetVersion(draft); return reloadCatalogVersion(draft.getPsvId(), priceType); } @@ -386,12 +519,12 @@ public class CatalogVersionSupport productMapper.updatePriceTypeByPsvId(draft.getPsvId(), priceType); detailMapper.updatePriceTypeByPsvId(draft.getPsvId(), priceType); } - draft.setPriceBuildMode("COPY"); + draft.setPriceBuildMode(mode); versionMapper.updatePrcPriceSetVersion(draft); } else if (count == 0) { - draft.setPriceBuildMode("IMPORT"); + draft.setPriceBuildMode(mode); versionMapper.updatePrcPriceSetVersion(draft); } return reloadCatalogVersion(draft.getPsvId(), priceType); diff --git a/bms-back/bms-system/src/main/java/com/bms/system/service/impl/BmsRegionSyncServiceImpl.java b/bms-back/bms-system/src/main/java/com/bms/system/service/impl/BmsRegionSyncServiceImpl.java index dea33e32..c81791ee 100644 --- a/bms-back/bms-system/src/main/java/com/bms/system/service/impl/BmsRegionSyncServiceImpl.java +++ b/bms-back/bms-system/src/main/java/com/bms/system/service/impl/BmsRegionSyncServiceImpl.java @@ -117,6 +117,11 @@ public class BmsRegionSyncServiceImpl implements IBmsRegionSyncService if (existing != null) { region.setRegionId(existing.getRegionId()); + // 已绑定到 OSS 的国旗不随外部图片地址覆盖,避免同步后国旗错位或丢失 + if (isOwnFlag(existing.getFlagUrl())) + { + region.setFlagUrl(existing.getFlagUrl()); + } regionMapper.updateRegion(region); updateCount++; } @@ -261,4 +266,11 @@ public class BmsRegionSyncServiceImpl implements IBmsRegionSyncService return region; } + + /** 已经上传到本系统 OSS 的国旗地址,同步时保留。 */ + private boolean isOwnFlag(String flagUrl) + { + return StringUtils.isNotEmpty(flagUrl) + && (flagUrl.startsWith("oss://") || flagUrl.contains("/region/flag/")); + } } diff --git a/bms-back/bms-system/src/main/resources/mapper/ar/ArBalanceWriteoffMapper.xml b/bms-back/bms-system/src/main/resources/mapper/ar/ArBalanceWriteoffMapper.xml index 852f39fb..3ddd6c46 100644 --- a/bms-back/bms-system/src/main/resources/mapper/ar/ArBalanceWriteoffMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/ar/ArBalanceWriteoffMapper.xml @@ -77,22 +77,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where writeoff_id = #{writeoffId} and status = #{effectiveStatus} - - and w.customer_id = #{customerId} - and w.ar_bill_id = #{arBillId} - and w.status = #{status} - and w.currency = #{currency} - and w.writeoff_no like concat('%', #{writeoffNo}, '%') - and w.bill_no like concat('%', #{billNo}, '%') - and w.receipt_id = #{receiptId} - - and date_format(w.writeoff_date,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + and w.customer_id = #{query.customerId} + and w.ar_bill_id = #{query.arBillId} + and w.status = #{query.status} + and w.currency = #{query.currency} + and w.writeoff_no like concat('%', #{query.writeoffNo}, '%') + and w.bill_no like concat('%', #{query.billNo}, '%') + and w.receipt_id = #{query.receiptId} + + and date_format(w.writeoff_date,'%y%m%d') >= date_format(#{query.params.beginTime},'%y%m%d') - - and date_format(w.writeoff_date,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + + and date_format(w.writeoff_date,'%y%m%d') <= date_format(#{query.params.endTime},'%y%m%d') + order by w.create_time desc, w.writeoff_id desc diff --git a/bms-back/bms-system/src/main/resources/mapper/ar/ArBillDetailFeeMapper.xml b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillDetailFeeMapper.xml index a4347a19..3866eeb9 100644 --- a/bms-back/bms-system/src/main/resources/mapper/ar/ArBillDetailFeeMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillDetailFeeMapper.xml @@ -78,6 +78,34 @@ order by f.fee_no, f.detail_fee_id + + + + + + + diff --git a/bms-back/bms-system/src/main/resources/mapper/ar/ArBillMapper.xml b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillMapper.xml index e695f45e..ed8d8445 100644 --- a/bms-back/bms-system/src/main/resources/mapper/ar/ArBillMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillMapper.xml @@ -76,34 +76,35 @@ and (generation_status is null or generation_status = 'READY') - and bill_no like concat('%', #{billNo}, '%') - and bill_name like concat('%', #{billName}, '%') - and customer_code like concat('%', #{customerCode}, + and bill_no like concat('%', #{query.billNo}, '%') + and bill_name like concat('%', #{query.billName}, '%') + and customer_code like concat('%', #{query.customerCode}, '%') - and customer_name like concat('%', #{customerName}, + and customer_name like concat('%', #{query.customerName}, '%') - and customer_id = #{customerId} - and status = #{status} - and currency = #{currency} - and bill_date >= #{billDateStart} - and bill_date <= #{billDateEnd} - and bill_period_end = #{billPeriodEnd} + and customer_id = #{query.customerId} + and status = #{query.status} + and currency = #{query.currency} + and bill_date >= #{query.billDateStart} + and bill_date <= #{query.billDateEnd} + and bill_period_end = #{query.billPeriodEnd} + - + select b.* from ar_bill b order by create_time desc, ar_bill_id desc - select coalesce(sum(total_amount), 0) as total_amount, coalesce(sum(written_off_amount), 0) as written_off_amount, coalesce(sum(unwritten_amount), 0) as unwritten_amount - from ar_bill + from ar_bill b @@ -112,6 +113,11 @@ where ar_bill_id = #{arBillId} + + diff --git a/bms-back/bms-system/src/main/resources/mapper/ar/ArBillScopeMapper.xml b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillScopeMapper.xml new file mode 100644 index 00000000..90c88d43 --- /dev/null +++ b/bms-back/bms-system/src/main/resources/mapper/ar/ArBillScopeMapper.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + AND c.del_flag = '0' + AND EXISTS ( + SELECT 1 FROM sys_user su + WHERE CAST(su.user_id AS CHAR) = c.sales_user_id AND su.del_flag = '0' + AND (1 = 0 + OR su.user_id = #{scope.userId} + OR su.dept_id = #{scope.deptId} + ) + ) + + AND 1 = 0 + + + + + + + + AND EXISTS (SELECT 1 FROM ctr_customer c WHERE c.customer_id = b.customer_id + + ) + + + + + + + diff --git a/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml b/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml index eed04e5e..8ac9eef2 100644 --- a/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/customer/BmsCustomerMapper.xml @@ -112,6 +112,55 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" order by c.customer_id desc + + + + + + + + + + + + + + + + + + + + + + insert into srv_service_channel ( + id, channel_code, channel_name, service_code, service_name, + bl_open, bl_multiple, cargo_type, pay_type, shipper_name, shipper_id, + query_type, trajectory_code, final_service_name, des_port, + weight_type, dim_divisor, weight_rule, shipment_type, data_from, remarks, + create_name, create_date, modifier, modify_date, gmt_create, gmt_modified + ) values ( + #{id}, #{channelCode}, #{channelName}, #{serviceCode}, #{serviceName}, + #{blOpen}, #{blMultiple}, #{cargoType}, #{payType}, #{shipperName}, #{shipperId}, + #{queryType}, #{trajectoryCode}, #{finalServiceName}, #{desPort}, + #{weightType}, #{dimDivisor}, #{weightRule}, #{shipmentType}, #{dataFrom}, #{remarks}, + #{createName}, sysdate(), #{modifier}, sysdate(), sysdate(), sysdate() + ) + + + + update srv_service_channel + set channel_code = #{channelCode}, + channel_name = #{channelName}, + service_code = #{serviceCode}, + service_name = #{serviceName}, + bl_open = #{blOpen}, + bl_multiple = #{blMultiple}, + cargo_type = #{cargoType}, + pay_type = #{payType}, + shipper_name = #{shipperName}, + shipper_id = #{shipperId}, + query_type = #{queryType}, + trajectory_code = #{trajectoryCode}, + final_service_name = #{finalServiceName}, + des_port = #{desPort}, + weight_type = #{weightType}, + dim_divisor = #{dimDivisor}, + weight_rule = #{weightRule}, + shipment_type = #{shipmentType}, + data_from = #{dataFrom}, + remarks = #{remarks}, + modifier = #{modifier}, + modify_date = sysdate(), + gmt_modified = sysdate() + where id = #{id} + + + + update srv_service_channel + set bl_open = #{blOpen}, + modifier = #{modifier}, + modify_date = sysdate(), + gmt_modified = sysdate() + where id = #{id} + + + + delete from srv_service_channel where id in + + #{id} + + diff --git a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml index 24e368a6..27b253e5 100644 --- a/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml +++ b/bms-back/bms-system/src/main/resources/mapper/price/BmsProductMapper.xml @@ -45,14 +45,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ifnull(p.is_del, '0') as is_del, p.source_sheet, null as remark, null as tms_id, v.created_by, p.create_time, v.updated_by, p.update_time, - (select count(distinct ifnull(c.country_code, c.country_name)) from prc_price_set_detail c - where ifnull(c.is_del, '0') = '0' - and (c.psp_id = p.psp_id or (c.psv_id = p.psv_id and c.product_code = p.product_code)) - ) as country_count, - (select count(*) from prc_surcharge_rel r - inner join prc_surcharge s on s.sc_id = r.sc_id and ifnull(s.is_del, '0') = '0' - where ifnull(r.is_del, '0') = '0' - and r.product_id = p.psp_id and r.price_type = 'PRODUCT') as surcharge_count + null as country_count, null as surcharge_count from prc_price_set_product p inner join prc_price_set_version v on v.psv_id = p.psv_id @@ -176,6 +169,66 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + + + insert into prc_price_set_product ( price_type, psv_id, product_code, product_name, service_level, cargo_attr, diff --git a/bms-back/sql/bms_init.sql b/bms-back/sql/bms_init.sql index 9d3dbc6f..581cfe62 100644 --- a/bms-back/sql/bms_init.sql +++ b/bms-back/sql/bms_init.sql @@ -1298,7 +1298,7 @@ CREATE TABLE `prc_price_set_version` ( `effective_time` datetime DEFAULT NULL COMMENT '生效时间', `expire_time` datetime DEFAULT NULL COMMENT '失效时间(空=长期;下一版本启动时写入该启动时间)', `status` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '0 draft 3 pending 1 effect 2 expired', - `price_build_mode` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建价格方式 PULL=拉取产品库 IMPORT=Excel继承上一版 IMPORT_FRESH=Excel重新建价', + `price_build_mode` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建价格方式 SALES:PULL/IMPORT/IMPORT_FRESH; PRODUCT/REDLINE:IMPORT=沿用生效版 IMPORT_FRESH=重新建价', `is_del` char(1) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否删除 0未删除 1已删除', `created_by` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建人', `create_time` datetime DEFAULT NULL COMMENT '创建时间', diff --git a/bms-back/sql/data/region_flag_oss.sql b/bms-back/sql/data/region_flag_oss.sql new file mode 100644 index 00000000..5647a0db --- /dev/null +++ b/bms-back/sql/data/region_flag_oss.sql @@ -0,0 +1,251 @@ +-- 区域国旗全部改为 OSS 地址 +-- 上次约 104 条能看到图,是因为只有这些行原来写了 flagcdn 地址,其余 flag_url 为空 +-- 本次只按国家两位码更新,中文名写法不同也不会漏 +SET NAMES utf8mb4; + +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ad.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ae.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/af.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ag.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ai.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/al.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/am.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ao.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ar.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/as.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/at.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/au.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/aw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ax.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AX'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/az.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'AZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ba.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bb.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BB'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bd.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/be.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bi.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bj.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BJ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bo.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bq.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BQ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/br.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bs.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/by.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/bz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'BZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ca.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cd.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ch.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ci.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ck.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/co.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cv.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CV'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cx.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CX'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cy.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/cz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'CZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/de.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/dj.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DJ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/dk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/dm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/do.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/dz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'DZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ec.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'EC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ee.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'EE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/eg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'EG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/eh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'EH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/er.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ER'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/es.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ES'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/et.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ET'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/fi.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'FI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/fj.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'FJ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/fk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'FK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/fo.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'FO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/fr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'FR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ga.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gb.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GB'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gd.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ge.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gi.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gp.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GP'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gq.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GQ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gs.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/gy.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'GY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/hk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'HK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/hn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'HN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/hr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'HR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ht.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'HT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/hu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'HU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/id.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ID'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ie.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/il.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/im.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/in.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/io.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/iq.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IQ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ir.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/is.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/it.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'IT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/je.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'JE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/jm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'JM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/jo.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'JO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/jp.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'JP'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ke.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ki.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/km.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kp.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KP'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ky.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/kz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'KZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/la.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lb.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LB'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/li.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ls.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/lv.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LV'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ly.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'LY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ma.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/md.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/me.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ME'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ml.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ML'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mo.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mp.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MP'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mq.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MQ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ms.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mv.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MV'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mx.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MX'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/my.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/mz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'MZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/na.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ne.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ng.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ni.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/no.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/np.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NP'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/nz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'NZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/om.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'OM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pa.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pe.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ph.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ps.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/pw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/py.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'PY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/qa.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'QA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/re.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'RE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ro.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'RO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/rs.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'RS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ru.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'RU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/rw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'RW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sa.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sb.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SB'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sd.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/se.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sh.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/si.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sj.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SJ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/so.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ss.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/st.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ST'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sv.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SV'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sx.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SX'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sy.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/sz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'SZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/td.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TD'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/th.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TH'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tj.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TJ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tl.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TL'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/to.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TO'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tr.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TR'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tv.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TV'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TW'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/tz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'TZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ua.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'UA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ug.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'UG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/um.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'UM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/us.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'US'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/uy.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'UY'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/uz.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'UZ'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/va.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/vc.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VC'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ve.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/vg.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VG'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/vi.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VI'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/vn.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VN'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/vu.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'VU'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/wf.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'WF'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ws.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'WS'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/xk.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'XK'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/ye.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'YE'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/yt.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'YT'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/za.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ZA'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/zm.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ZM'; +UPDATE region SET flag_url = 'https://oss.lionquexpress.com/bms/prod/region/flag/zw.png', update_time = sysdate() WHERE del_flag = '0' AND country_code_2 = 'ZW'; diff --git a/bms-back/sql/data/service_channel_menu.sql b/bms-back/sql/data/service_channel_menu.sql new file mode 100644 index 00000000..b10b0de7 --- /dev/null +++ b/bms-back/sql/data/service_channel_menu.sql @@ -0,0 +1,68 @@ +-- 数据管理 - 渠道管理 +-- 权限:data:serviceChannel:list|query|add|edit|remove|export +-- 启用/停用走修改权限 data:serviceChannel:edit +SET NAMES utf8mb4; + +SET @parentId := ( + SELECT menu_id FROM sys_menu + WHERE path = 'data' AND menu_type = 'M' AND parent_id = 0 + ORDER BY menu_id ASC LIMIT 1 +); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, route_name, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT 2502, N'渠道管理', @parentId, 3, 'serviceChannel', 'data/serviceChannel/index', '', 'ServiceChannel', 1, 0, 'C', '0', '0', 'data:serviceChannel:list', 'guide', 'admin', sysdate(), N'服务渠道维护,数据表 srv_service_channel' +FROM DUAL WHERE @parentId IS NOT NULL AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2502 OR perms = 'data:serviceChannel:list'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2503, N'查询', 2502, 1, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:query', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2503 OR perms = 'data:serviceChannel:query'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2504, N'新增', 2502, 2, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:add', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2504 OR perms = 'data:serviceChannel:add'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2505, N'修改', 2502, 3, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:edit', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2505 OR perms = 'data:serviceChannel:edit'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2506, N'删除', 2502, 4, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:remove', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2506 OR perms = 'data:serviceChannel:remove'); + +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time) +SELECT 2507, N'导出', 2502, 5, '', NULL, 1, 0, 'F', '0', '0', 'data:serviceChannel:export', '#', 'admin', sysdate() +FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2507 OR perms = 'data:serviceChannel:export'); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT 1, m.menu_id FROM ( + SELECT 2502 AS menu_id UNION SELECT 2503 UNION SELECT 2504 UNION SELECT 2505 UNION SELECT 2506 UNION SELECT 2507 +) m +WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 1 AND rm.menu_id = m.menu_id); + +-- 已有「数据管理-区域管理」权限的角色,同步授予对应的渠道管理权限 +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT DISTINCT rm.role_id, dst.menu_id +FROM sys_role_menu rm +JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:list' +JOIN sys_menu dst ON dst.perms IN ('data:serviceChannel:list', 'data:serviceChannel:query', 'data:serviceChannel:export') +WHERE NOT EXISTS ( + SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id +); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT DISTINCT rm.role_id, dst.menu_id +FROM sys_role_menu rm +JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:edit' +JOIN sys_menu dst ON dst.perms IN ('data:serviceChannel:add', 'data:serviceChannel:edit') +WHERE NOT EXISTS ( + SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id +); + +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT DISTINCT rm.role_id, dst.menu_id +FROM sys_role_menu rm +JOIN sys_menu src ON src.menu_id = rm.menu_id AND src.perms = 'data:region:remove' +JOIN sys_menu dst ON dst.perms = 'data:serviceChannel:remove' +WHERE NOT EXISTS ( + SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = dst.menu_id +); diff --git a/bms-back/sql/price/prc_catalog_price_build_mode_import_fresh.sql b/bms-back/sql/price/prc_catalog_price_build_mode_import_fresh.sql new file mode 100644 index 00000000..bf920d2f --- /dev/null +++ b/bms-back/sql/price/prc_catalog_price_build_mode_import_fresh.sql @@ -0,0 +1,15 @@ +-- Catalog (PRODUCT / REDLINE) price_build_mode rename: +-- COPY → IMPORT (按现有生效版本建价) +-- IMPORT → IMPORT_FRESH (重新建产品价) +-- Order matters: migrate old IMPORT first, then COPY. +SET NAMES utf8mb4; + +UPDATE prc_price_set_version +SET price_build_mode = 'IMPORT_FRESH' +WHERE price_type IN ('PRODUCT', 'REDLINE') + AND UPPER(IFNULL(price_build_mode, '')) = 'IMPORT'; + +UPDATE prc_price_set_version +SET price_build_mode = 'IMPORT' +WHERE price_type IN ('PRODUCT', 'REDLINE') + AND UPPER(IFNULL(price_build_mode, '')) = 'COPY'; diff --git a/bms-back/sql/price/prc_price_set_version_price_build_mode_alter.sql b/bms-back/sql/price/prc_price_set_version_price_build_mode_alter.sql index 5f20dac9..c586dc9a 100644 --- a/bms-back/sql/price/prc_price_set_version_price_build_mode_alter.sql +++ b/bms-back/sql/price/prc_price_set_version_price_build_mode_alter.sql @@ -1,3 +1,3 @@ -- Add create-price mode on package version: PULL / IMPORT ALTER TABLE prc_price_set_version - ADD COLUMN price_build_mode varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建价格方式 PULL=拉取产品库 IMPORT=Excel继承上一版 IMPORT_FRESH=Excel重新建价' AFTER status; + ADD COLUMN price_build_mode varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '创建价格方式 SALES:PULL/IMPORT/IMPORT_FRESH; PRODUCT/REDLINE:IMPORT=沿用生效版 IMPORT_FRESH=重新建价' AFTER status; diff --git a/bms-front/src/api/ar/bill.js b/bms-front/src/api/ar/bill.js index bb82aee1..6e080c87 100644 --- a/bms-front/src/api/ar/bill.js +++ b/bms-front/src/api/ar/bill.js @@ -1,5 +1,13 @@ import request from '@/utils/request' +export function listArBillCustomerOptions(query) { + return request({ url: '/ar/bill/customer-options', method: 'get', params: query }) +} + +export function listArBillGenerateCustomerOptions(query) { + return request({ url: '/ar/bill/generate/customer-options', method: 'get', params: query }) +} + // 应收账单接口统一放在这里;生成和导出均为异步任务,提交接口不等待后台处理完成。 export function listArBill(query) { return request({ url: '/ar/bill/list', method: 'get', params: query }) diff --git a/bms-front/src/api/customersuppliermanagement/customerinfo/customer.js b/bms-front/src/api/customersuppliermanagement/customerinfo/customer.js index 60444d95..158877d5 100644 --- a/bms-front/src/api/customersuppliermanagement/customerinfo/customer.js +++ b/bms-front/src/api/customersuppliermanagement/customerinfo/customer.js @@ -9,6 +9,25 @@ export function listCustomer(query) { }) } +// 分页查询未关联业务员的客户 +export function listUnlinkedSalesUserCustomers(query) { + return request({ + url: '/customersupplier/customerinfo/unlinked-sales-user/list', + method: 'get', + params: query + }) +} + +// 客户下拉选项:只返回客户ID、客户编码、客户名称 +// keywords 按客户名称、客户编码、对外代码模糊查询 +export function listCustomerOption(query) { + return request({ + url: '/customersupplier/customerinfo/optionselect', + method: 'get', + params: query + }) +} + // 查询客户主详细 export function getCustomer(customerId) { return request({ diff --git a/bms-front/src/api/masterdata/serviceChannel.js b/bms-front/src/api/masterdata/serviceChannel.js index 61b02833..b8968351 100644 --- a/bms-front/src/api/masterdata/serviceChannel.js +++ b/bms-front/src/api/masterdata/serviceChannel.js @@ -1,5 +1,14 @@ import request from '@/utils/request' +/** 分页查询渠道列表 */ +export function listServiceChannel(query) { + return request({ + url: '/masterdata/servicechannel/list', + method: 'get', + params: query + }) +} + /** 服务渠道下拉选项(非分页,来源 srv_service_channel 老系统镜像) */ export function listChannelOptions(query) { return request({ @@ -8,3 +17,46 @@ export function listChannelOptions(query) { params: query }) } + +/** 查询渠道详情 */ +export function getServiceChannel(id) { + return request({ + url: '/masterdata/servicechannel/' + id, + method: 'get' + }) +} + +/** 新增渠道 */ +export function addServiceChannel(data) { + return request({ + url: '/masterdata/servicechannel', + method: 'post', + data: data + }) +} + +/** 修改渠道 */ +export function updateServiceChannel(data) { + return request({ + url: '/masterdata/servicechannel', + method: 'put', + data: data + }) +} + +/** 启用或停用渠道 */ +export function changeServiceChannelStatus(id, blOpen) { + return request({ + url: '/masterdata/servicechannel/changeStatus', + method: 'put', + data: { id, blOpen } + }) +} + +/** 删除渠道 */ +export function delServiceChannel(ids) { + return request({ + url: '/masterdata/servicechannel/' + ids, + method: 'delete' + }) +} diff --git a/bms-front/src/api/price/set.js b/bms-front/src/api/price/set.js index 7bbe9b52..66adfbc3 100644 --- a/bms-front/src/api/price/set.js +++ b/bms-front/src/api/price/set.js @@ -198,6 +198,15 @@ export function listSetDetailByProduct(psvId, productCode) { }) } +/** All detail rows for a version (no pagination); one call instead of N byProduct. */ +export function listSetDetailByVersion(psvId) { + return request({ + url: '/price/set/detail/byVersion', + method: 'get', + params: { psvId } + }) +} + /** 版本明细搜索下拉选项:按版本去重后的 产品/国家/分区 */ export function listSetDetailOptions(psvId) { return request({ diff --git a/bms-front/src/components/CustomerSelect/index.vue b/bms-front/src/components/CustomerSelect/index.vue index 23377611..b47e2a1e 100644 --- a/bms-front/src/components/CustomerSelect/index.vue +++ b/bms-front/src/components/CustomerSelect/index.vue @@ -32,10 +32,15 @@ + + diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue index 9082a236..0a9b1060 100644 --- a/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue +++ b/bms-front/src/views/customersuppliermanagement/customerinfo/customeredit/index.vue @@ -661,7 +661,6 @@ filterable placeholder="请选择生效中的套餐" style="width: 100%;" - @change="onPriceSetChange" >
数字越小优先级越高,1 为最高
- - - - - - - - - - - - @@ -835,8 +810,7 @@ const priceSetForm = ref({}) const priceSetRules = { priceSetId: [{ required: true, message: '请选择价格套餐', trigger: 'change' }], - bindPriority: [{ required: true, message: '优先级不能为空', trigger: 'blur' }], - prBegindate: [{ required: true, message: '绑定生效日期不能为空', trigger: 'change' }] + bindPriority: [{ required: true, message: '优先级不能为空', trigger: 'blur' }] } const selectedPriceSet = computed(() => @@ -871,26 +845,18 @@ function openPriceSetDialog(row) { ensurePriceSetOptions() priceSetForm.value = row ? { ...row } - : { priceSetId: null, bindPriority: 1, prBegindate: null, prEnddate: null, priceSetNote: null } + : { priceSetId: null, bindPriority: 1, priceSetNote: null } priceSetDialogTitle.value = row || boundPriceSets.value.length ? '更换套餐' : '绑定套餐' priceSetDialogVisible.value = true nextTick(() => proxy.$refs['priceSetRef'] && proxy.$refs['priceSetRef'].clearValidate()) } -/** 选择套餐后,生效日期未填时默认今天 */ -function onPriceSetChange(priceSetId) { - if (!priceSetId || priceSetForm.value.prBegindate) return - priceSetForm.value.prBegindate = proxy.parseTime(new Date(), '{y}-{m}-{d}') -} - function submitPriceSetForm() { proxy.$refs['priceSetRef'].validate(valid => { if (!valid) return - if (priceSetForm.value.prEnddate && priceSetForm.value.prBegindate > priceSetForm.value.prEnddate) { - proxy.$modal.msgWarning('失效日期不能早于生效日期') - return - } const payload = { ...priceSetForm.value, customerId: form.value.customerId } + delete payload.prBegindate + delete payload.prEnddate priceSetSaving.value = true saveCustomerPriceSet(payload).then(() => { proxy.$modal.msgSuccess('保存成功') diff --git a/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue b/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue index 36373df0..feba56cc 100644 --- a/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue +++ b/bms-front/src/views/customersuppliermanagement/customerinfo/index.vue @@ -114,6 +114,15 @@ v-hasPermi="['customersupplier:customerinfo:remove']" >删除 + + 未关联业务员 + - - - - - - - - - - - -
数字越小优先级越高,1 为最高
@@ -302,6 +297,8 @@ :customer-name="billCustomer.customerName" /> + + { if (!valid) return - if (batchForm.value.prEnddate && batchForm.value.prBegindate > batchForm.value.prEnddate) { - proxy.$modal.msgWarning('失效日期不能早于生效日期') - return - } const total = selectedRows.value.length const bound = boundCount.value const setName = (priceSetOptions.value.find(o => o.priceSetId === batchForm.value.priceSetId) || {}).priceSetName || '' @@ -602,8 +594,6 @@ function submitBatchBind() { customerIds: selectedRows.value.map(r => r.customerId), priceSetId: batchForm.value.priceSetId, bindPriority: batchForm.value.bindPriority, - prBegindate: batchForm.value.prBegindate, - prEnddate: batchForm.value.prEnddate, priceSetNote: batchForm.value.priceSetNote, overwriteExisting: batchForm.value.overwriteExisting }) diff --git a/bms-front/src/views/data/region/index.vue b/bms-front/src/views/data/region/index.vue index 7133a192..97a8df54 100644 --- a/bms-front/src/views/data/region/index.vue +++ b/bms-front/src/views/data/region/index.vue @@ -70,7 +70,8 @@