Compare commits

..

2 Commits

Author SHA1 Message Date
一休哥哥6666
2991dd88bb feat:增加换货单的逻辑,已发货短信模板更改 2026-06-15 13:42:52 +08:00
一休哥哥6666
dfef98814b feat:新增配片单重复打开的缓存问题,已发货短信 2026-06-14 16:31:41 +08:00
28 changed files with 586 additions and 634 deletions

View File

@@ -114,23 +114,6 @@ export function rejectExchangeOrder(data) {
})
}
// 拒绝换货申请订单完成
export function completeExchangeRejectedOrder(data) {
return request({
url: '/jysystem/order/exchangeRejectedComplete',
method: 'put',
data: data
})
}
// 批量将拒绝换货申请订单更新为已完成
export function completeAllExchangeRejectedOrder() {
return request({
url: '/jysystem/order/exchangeRejectedCompleteAll',
method: 'put'
})
}
// 变更订单状态
export function changeOrderStatus(data) {
return request({

View File

@@ -172,15 +172,6 @@
@click="handleQuickFilter('exchangeRejected')"
>拒绝换货申请</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
size="mini"
@click="handleBatchCompleteExchangeRejected"
v-hasPermi="['jysystem:order:edit']"
>更新拒绝换货申请为已完成</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
@@ -200,17 +191,22 @@
</el-table-column>
<el-table-column label="B价格" align="center" width="90">
<template slot-scope="scope">
<span>{{ formatPriceB(scope.row) }}</span>
<span>{{ formatPriceAmount(formatPriceB(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="C价格" align="center" width="90">
<template slot-scope="scope">
<span>{{ formatPriceC(scope.row) }}</span>
<span>{{ formatPriceAmount(formatPriceC(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="物流费用" align="center" width="90">
<template slot-scope="scope">
<span>{{ formatPriceAmount(formatLogisticsFee(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="渐进多焦点价格" align="center" width="120">
<template slot-scope="scope">
<span>{{ formatProgressiveMultifocalPrice(scope.row) }}</span>
<span>{{ formatPriceAmount(formatProgressiveMultifocalPrice(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="订单状态" align="center" prop="orderStatus" width="130">
@@ -850,21 +846,21 @@
</el-descriptions-item>
<el-descriptions-item label="B合计">
<el-tag
v-if="isPendingTagText(formatPriceAmount(formatPriceTotal(detail, 'priceB')))"
v-if="isPendingTagText(formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')))"
type="danger"
size="small"
:disable-transitions="true"
>{{ formatPriceAmount(formatPriceTotal(detail, 'priceB')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatPriceTotal(detail, 'priceB')) }}</span>
>{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</span>
</el-descriptions-item>
<el-descriptions-item label="C合计">
<el-tag
v-if="isPendingTagText(formatPriceAmount(formatPriceTotal(detail, 'priceC')))"
v-if="isPendingTagText(formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')))"
type="danger"
size="small"
:disable-transitions="true"
>{{ formatPriceAmount(formatPriceTotal(detail, 'priceC')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatPriceTotal(detail, 'priceC')) }}</span>
>{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')) }}</span>
</el-descriptions-item>
</el-descriptions>
<div class="detail-logistics-fee-block">
@@ -876,26 +872,6 @@
<span>{{ formatPriceAmount(formatLogisticsLogFee(scope.row, detail)) }}</span>
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" width="120">
<template slot-scope="scope">
<span>{{ formatShipDate(scope.row.operateTime) }}</span>
@@ -1021,26 +997,6 @@
<dict-tag :options="dict.type.jy_order_status" :value="scope.row.orderStatus" />
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="160" show-overflow-tooltip />
<el-table-column label="操作人" align="center" prop="operator" width="100" />
<el-table-column label="操作时间" align="center" prop="operateTime" width="160" />
@@ -1124,7 +1080,7 @@
/>
</el-form-item>
<el-alert
title="仅汇总所选年月内已完成状态的订单品牌方生成应收(AR)镜片厂生成应付(AP)"
title="仅汇总所选年月内已完成或换货完成状态的订单品牌方生成应收(AR)镜片厂生成应付(AP)"
type="info"
:closable="false"
show-icon
@@ -1142,7 +1098,7 @@
import axios from 'axios'
import { getToken } from '@/utils/auth'
import { isExternal } from '@/utils/validate'
import { listOrder, getOrder, getOrderLogistics, delOrder, addOrder, updateOrder, previewAssignPrice, assignOrder, rejectOrder, closeOrder, completeOrder, agreeExchangeOrder, rejectExchangeOrder, completeExchangeRejectedOrder, completeAllExchangeRejectedOrder, changeOrderStatus } from "@/api/jysystem/order";
import { listOrder, getOrder, getOrderLogistics, delOrder, addOrder, updateOrder, previewAssignPrice, assignOrder, rejectOrder, closeOrder, completeOrder, agreeExchangeOrder, rejectExchangeOrder, changeOrderStatus } from "@/api/jysystem/order";
import { checkPermi } from "@/utils/permission";
import { listBrandTenant, listLensFactoryTenant } from "@/api/jysystem/tenant";
import { listLensOptions } from "@/api/jysystem/lens";
@@ -1216,6 +1172,9 @@ export default {
ORDER_STATUS_SHIPPED: '8',
ORDER_STATUS_COMPLETED: '9',
ORDER_STATUS_EXCHANGE_APPLY: '12',
ORDER_STATUS_EXCHANGE_AGREED: '13',
ORDER_STATUS_EXCHANGE_LOGISTICS: '15',
ORDER_STATUS_EXCHANGE_COMPLETED: '17',
ORDER_STATUS_EXCHANGE_REJECTED: '21',
logisticsDialogVisible: false,
logisticsBasic: null,
@@ -1368,20 +1327,42 @@ export default {
},
formatPriceB(row) {
if (!row) return '-';
if (this.isExchangeOrder(row)) return '-';
if (this.isPendingAssign(row)) return '未核算';
return row.priceB != null ? row.priceB : '-';
},
formatPriceC(row) {
if (!row) return '-';
if (this.isExchangeOrder(row)) return '-';
if (this.isPendingAssign(row)) return '未核算';
return row.priceC != null ? row.priceC : '-';
},
formatProgressiveMultifocalPrice(row) {
if (!row) return '-';
if (this.isExchangeOrder(row)) return '-';
if (Number(row.progressiveMultifocal) !== 1) return '-';
if (this.isPendingAssign(row)) return '未核算';
return row.progressiveMultifocalPrice != null ? row.progressiveMultifocalPrice : '-';
},
isExchangeOrder(row) {
if (!row) return false;
if (row.orderNo && String(row.orderNo).startsWith('HH')) return true;
const status = row.orderStatus != null ? String(row.orderStatus) : '';
return status === this.ORDER_STATUS_EXCHANGE_APPLY
|| status === this.ORDER_STATUS_EXCHANGE_AGREED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED;
},
formatDetailPriceTotal(detail, priceKey) {
if (this.isExchangeOrder(detail)) return this.formatDetailLogisticsFee(detail);
return this.formatPriceTotal(detail, priceKey);
},
formatLogisticsFee(row) {
if (!row) return '-';
if (!this.isExchangeOrder(row)) return '-';
const fee = this.parseLogisticsFeeValue(row.logisticsFee);
return fee != null ? fee : '-';
},
formatPriceBC(row) {
return `${this.formatPriceB(row)} / ${this.formatPriceC(row)}`;
},
@@ -1430,7 +1411,7 @@ export default {
hasFee = true;
}
});
if (!hasFee && logs.length > 0 && detail.logisticsFee != null) {
if (!hasFee && detail.logisticsFee != null) {
const legacyFee = this.parseLogisticsFeeValue(detail.logisticsFee);
if (legacyFee != null) return legacyFee;
}
@@ -1440,24 +1421,6 @@ export default {
formatDetailLogisticsFee(detail) {
return this.sumDetailLogisticsFee(detail);
},
formatLogSaleSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null;
}
if (log.saleSettleStatus != null && log.saleSettleStatus !== '') {
return log.saleSettleStatus;
}
return '0';
},
formatLogPurchaseSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null;
}
if (log.purchaseSettleStatus != null && log.purchaseSettleStatus !== '') {
return log.purchaseSettleStatus;
}
return '0';
},
formatShipDate(time) {
if (!time) {
return '-';
@@ -1730,13 +1693,17 @@ export default {
},
canViewLogistics(row) {
if (!row || row.orderStatus == null) return false;
const status = Number(row.orderStatus);
return status === Number(this.ORDER_STATUS_SHIPPED) || status === 9;
const status = String(row.orderStatus);
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_COMPLETED
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED;
},
canCompleteOrder(row) {
if (!row || row.orderStatus == null) return false;
const status = String(row.orderStatus);
return status === this.ORDER_STATUS_SHIPPED || status === this.ORDER_STATUS_EXCHANGE_REJECTED;
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS;
},
handleViewLogistics(row) {
if (!row || !row.id) return;
@@ -1864,28 +1831,13 @@ export default {
if (!row || !row.id) {
return;
}
const isExchangeRejected = String(row.orderStatus) === this.ORDER_STATUS_EXCHANGE_REJECTED;
const confirmMsg = isExchangeRejected
? `确认将拒绝换货申请订单"${row.orderNo}"标记为已完成吗?`
: `确认完成订单"${row.orderNo}"吗?`;
const requestFn = isExchangeRejected
? () => completeExchangeRejectedOrder({ orderId: row.id })
: () => completeOrder({ orderId: row.id });
this.$modal.confirm(confirmMsg).then(() => {
return requestFn();
this.$modal.confirm(`确认完成订单"${row.orderNo}"吗?`).then(() => {
return completeOrder({ orderId: row.id });
}).then(() => {
this.$modal.msgSuccess('操作成功');
this.getList();
}).catch(() => {});
},
handleBatchCompleteExchangeRejected() {
this.$modal.confirm('确认将所有拒绝换货申请状态的订单更新为已完成吗?').then(() => {
return completeAllExchangeRejectedOrder();
}).then((res) => {
this.$modal.msgSuccess((res && res.msg) || '操作成功');
this.getList();
}).catch(() => {});
},
handleAgreeExchange(row) {
if (!row || !row.id) {
return;

View File

@@ -55,7 +55,7 @@ public class ExpressQueryUtils {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "APPCODE " + appCode);
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.setContentType(MediaType.parseMediaType("application/x-www-form-urlencoded; charset=UTF-8"));
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
body.add("expressNo", expressNo);
@@ -75,21 +75,46 @@ public class ExpressQueryUtils {
return result;
} catch (HttpStatusCodeException e) {
int status = e.getRawStatusCode();
log.error("调用阿里云物流查询失败 expressNo={} status={}", expressNo, status, e);
String caError = e.getResponseHeaders() != null
? e.getResponseHeaders().getFirst("X-Ca-Error-Message") : null;
log.warn("调用阿里云物流查询失败 expressNo={} status={} caError={}", expressNo, status, caError);
result.put("errorCode", "HTTP_" + status);
if (status == 403) {
result.put("errorMsg", "物流查询服务授权失效HTTP 403请在阿里云 API 市场续费快递查询接口并更新 express.ali.app-code");
} else {
if (status == 403)
{
result.put("errorMsg", buildExpress403Message(caError));
}
else
{
String errorBody = e.getResponseBodyAsString();
result.put("errorMsg", StringUtils.isNotEmpty(errorBody) ? errorBody : ("物流查询请求失败HTTP状态码" + status));
}
return result;
} catch (Exception e) {
}
catch (Exception e)
{
log.error("调用阿里云物流查询失败 expressNo={}", expressNo, e);
result.put("errorCode", "EXCEPTION");
result.put("errorMsg", e.getMessage());
return result;
}
}
private String buildExpress403Message(String caError)
{
if (StringUtils.isEmpty(caError))
{
return "物流查询未授权HTTP 403请在阿里云 API 市场购买「快递物流查询」接口,"
+ "并使用该商品对应的 AppCode 配置 express.ali.app-code不能与实名认证等其它 API 混用)";
}
if (caError.contains("Quota") || caError.contains("quota") || caError.contains("exhausted"))
{
return "物流查询套餐次数已用完HTTP 403请在阿里云 API 市场续费快递查询接口";
}
if (caError.contains("Unauthorized") || caError.contains("Invalid AppCode") || caError.contains("not exists"))
{
return "物流查询 AppCode 无效或未订阅该 APIHTTP 403请更新 express.ali.app-code 为快递查询商品的 AppCode";
}
return "物流查询未授权HTTP 403" + caError;
}
}

View File

@@ -3,21 +3,6 @@ import store from '@/store'
import DataDict from '@/utils/dict'
import { getDicts as getDicts } from '@/api/system/dict/data'
function searchDictByKey(dict, key) {
if (key == null && key == "") {
return null
}
try {
for (let i = 0; i < dict.length; i++) {
if (dict[i].key == key) {
return dict[i].value
}
}
} catch (e) {
return null
}
}
function install() {
Vue.use(DataDict, {
metas: {
@@ -25,10 +10,6 @@ function install() {
labelField: 'dictLabel',
valueField: 'dictValue',
request(dictMeta) {
const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
if (storeDict) {
return new Promise(resolve => { resolve(storeDict) })
} else {
return new Promise((resolve, reject) => {
getDicts(dictMeta.type).then(res => {
store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
@@ -37,7 +18,6 @@ function install() {
reject(error)
})
})
}
},
},
},

View File

@@ -1,7 +1,7 @@
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<template v-if="values.includes(String(item.value))">
<span
v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
:key="item.value"
@@ -63,7 +63,7 @@ export default {
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
this.values.forEach(item => {
if (!this.options.some(v => v.value === item)) {
if (!this.options.some(v => String(v.value) === String(item))) {
this.unmatchArray.push(item)
unmatch = true // 如果有未匹配项将标志设置为true
}

View File

@@ -4,11 +4,16 @@ const state = {
const mutations = {
SET_DICT: (state, { key, value }) => {
if (key !== null && key !== "") {
const index = state.dict.findIndex(item => item.key === key)
if (index >= 0) {
state.dict.splice(index, 1, { key: key, value: value })
} else {
state.dict.push({
key: key,
value: value
})
}
}
},
REMOVE_DICT: (state, key) => {
try {

View File

@@ -30,7 +30,16 @@
<span>{{ formatLens(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="C价格" align="center" prop="priceC" width="80" />
<el-table-column label="C价格" align="center" width="80">
<template slot-scope="scope">
<span>{{ formatPriceAmount(formatPriceC(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="物流费用" align="center" width="90">
<template slot-scope="scope">
<span>{{ formatPriceAmount(formatLogisticsFee(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="渐进多焦点价格" align="center" min-width="100">
<template slot-scope="scope">
<span>{{ formatProgressiveMultifocalPrice(scope.row) }}</span>
@@ -187,11 +196,11 @@
</div>
<div class="section-body">
<el-descriptions :column="2" border size="small" class="detail-descriptions detail-descriptions--price">
<el-descriptions-item label="C价格">{{ formatPriceAmount(detail.priceC) }}</el-descriptions-item>
<el-descriptions-item label="C价格">{{ formatPriceAmount(formatPriceC(detail)) }}</el-descriptions-item>
<el-descriptions-item label="物流费用">{{ formatPriceAmount(formatDetailLogisticsFee(detail)) }}</el-descriptions-item>
<el-descriptions-item label="渐进多焦点价格">{{ formatPriceAmount(formatProgressiveMultifocalPrice(detail)) }}</el-descriptions-item>
<el-descriptions-item label="合计">
<span class="price-total-value">{{ formatPriceAmount(formatPriceTotal(detail, 'priceC')) }}</span>
<span class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceC')) }}</span>
</el-descriptions-item>
</el-descriptions>
<div class="detail-logistics-fee-block">
@@ -203,26 +212,6 @@
<span>{{ formatPriceAmount(formatLogisticsLogFee(scope.row, detail)) }}</span>
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" width="120">
<template slot-scope="scope">
<span>{{ formatShipDate(scope.row.operateTime) }}</span>
@@ -311,26 +300,6 @@
<dict-tag :options="dict.type.jy_order_status" :value="scope.row.orderStatus" />
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="160" show-overflow-tooltip />
<el-table-column label="操作人" align="center" prop="operator" width="100" />
<el-table-column label="操作时间" align="center" prop="operateTime" width="160" />
@@ -574,7 +543,10 @@ export default {
ORDER_STATUS_PRODUCING: '7',
ORDER_STATUS_SHIPPED: '8',
ORDER_STATUS_COMPLETED: '9',
ORDER_STATUS_EXCHANGE_APPLY: '12',
ORDER_STATUS_EXCHANGE_AGREED: '13',
ORDER_STATUS_EXCHANGE_LOGISTICS: '15',
ORDER_STATUS_EXCHANGE_COMPLETED: '17',
ORDER_STATUS_WITHDRAWN: '20',
ORDER_STATUS_SUPPLEMENTED: '19',
logisticsDialogVisible: false,
@@ -703,8 +675,32 @@ export default {
},
formatProgressiveMultifocalPrice(row) {
if (!row) return '-'
if (this.isExchangeOrder(row)) return '-'
return row.progressiveMultifocalPrice != null ? row.progressiveMultifocalPrice : '-'
},
isExchangeOrder(row) {
if (!row) return false
if (row.orderNo && String(row.orderNo).startsWith('HH')) return true
const status = row.orderStatus != null ? String(row.orderStatus) : ''
return status === this.ORDER_STATUS_EXCHANGE_APPLY || status === this.ORDER_STATUS_EXCHANGE_AGREED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED
},
formatLogisticsFee(row) {
if (!row) return '-'
if (!this.isExchangeOrder(row)) return '-'
const fee = this.parseLogisticsFeeValue(row.logisticsFee)
return fee != null ? fee : '-'
},
formatPriceC(row) {
if (!row) return '-'
if (this.isExchangeOrder(row)) return '-'
return row.priceC != null ? row.priceC : '-'
},
formatDetailPriceTotal(detail, priceKey) {
if (this.isExchangeOrder(detail)) return this.formatDetailLogisticsFee(detail)
return this.formatPriceTotal(detail, priceKey)
},
formatPriceAmount(value) {
if (value == null || value === '' || value === '-') return '-'
if (value === '未核算') return '未核算'
@@ -750,7 +746,7 @@ export default {
hasFee = true
}
})
if (!hasFee && logs.length > 0 && detail.logisticsFee != null) {
if (!hasFee && detail.logisticsFee != null) {
const legacyFee = this.parseLogisticsFeeValue(detail.logisticsFee)
if (legacyFee != null) return legacyFee
}
@@ -760,24 +756,6 @@ export default {
formatDetailLogisticsFee(detail) {
return this.sumDetailLogisticsFee(detail)
},
formatLogSaleSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null
}
if (log.saleSettleStatus != null && log.saleSettleStatus !== '') {
return log.saleSettleStatus
}
return '0'
},
formatLogPurchaseSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null
}
if (log.purchaseSettleStatus != null && log.purchaseSettleStatus !== '') {
return log.purchaseSettleStatus
}
return '0'
},
formatShipDate(time) {
if (!time) {
return '-'
@@ -915,12 +893,17 @@ export default {
},
canCompleteOrder(row) {
if (!row || row.orderStatus == null) return false
return String(row.orderStatus) === this.ORDER_STATUS_SHIPPED
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
},
canViewLogistics(row) {
if (!row || row.orderStatus == null) return false
const status = Number(row.orderStatus)
return status === Number(this.ORDER_STATUS_SHIPPED) || status === 9
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_COMPLETED
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED
},
handleViewLogistics(row) {
if (!row || !row.id) return

View File

@@ -73,6 +73,11 @@
<span v-else>{{ formatPriceB(scope.row) }}</span>
</template>
</el-table-column>
<el-table-column label="物流费用" align="center" width="90">
<template slot-scope="scope">
<span>{{ formatPriceAmount(formatLogisticsFee(scope.row)) }}</span>
</template>
</el-table-column>
<el-table-column label="渐进多焦点价格" align="center" min-width="100">
<template slot-scope="scope">
<el-tag
@@ -190,6 +195,7 @@
append-to-body
destroy-on-close
custom-class="lens-order-form-dialog"
@closed="handleFormClosed"
>
<div slot="title" class="lens-dialog-header">
<div class="lens-dialog-title-wrap">
@@ -197,7 +203,7 @@
<p class="lens-dialog-subtitle">{{ formDialogSubtitle }}</p>
</div>
</div>
<el-form ref="form" :model="form" :rules="rules" label-width="110px" class="lens-order-form">
<el-form :key="formDialogKey" ref="form" :model="form" :rules="rules" label-width="110px" class="lens-order-form">
<section class="lens-form-section">
<div class="section-head">
<span class="section-index">01</span>
@@ -670,12 +676,12 @@
</el-descriptions-item>
<el-descriptions-item label="合计">
<el-tag
v-if="isPendingTagText(formatPriceAmount(formatPriceTotal(detail, 'priceB')))"
v-if="isPendingTagText(formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')))"
type="danger"
size="small"
:disable-transitions="true"
>{{ formatPriceAmount(formatPriceTotal(detail, 'priceB')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatPriceTotal(detail, 'priceB')) }}</span>
>{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</el-tag>
<span v-else class="price-total-value">{{ formatPriceAmount(formatDetailPriceTotal(detail, 'priceB')) }}</span>
</el-descriptions-item>
</el-descriptions>
<div class="detail-logistics-fee-block">
@@ -687,26 +693,6 @@
<span>{{ formatPriceAmount(formatLogisticsLogFee(scope.row, detail)) }}</span>
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="发货日期" align="center" width="120">
<template slot-scope="scope">
<span>{{ formatShipDate(scope.row.operateTime) }}</span>
@@ -795,26 +781,6 @@
<dict-tag :options="dict.type.jy_order_status" :value="scope.row.orderStatus" />
</template>
</el-table-column>
<el-table-column label="应收结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogSaleSettleStatus(scope.row) != null"
:options="dict.type.jy_sale_settle_status"
:value="formatLogSaleSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="应付结算" align="center" width="100">
<template slot-scope="scope">
<dict-tag
v-if="formatLogPurchaseSettleStatus(scope.row) != null"
:options="dict.type.jy_purchase_settle_status"
:value="formatLogPurchaseSettleStatus(scope.row)"
/>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" min-width="160" show-overflow-tooltip />
<el-table-column label="操作人" align="center" prop="operator" width="100" />
<el-table-column label="操作时间" align="center" prop="operateTime" width="160" />
@@ -889,7 +855,7 @@
<span class="section-index">01</span>
<div class="section-text">
<h4>换货申请说明</h4>
<p>填写换货申请原因订单将进入换货申请状态</p>
<p>填写换货申请原因系统将复制当前订单生成新换货申请单原订单状态不变</p>
</div>
</div>
<div class="section-body">
@@ -1052,6 +1018,9 @@ export default {
ORDER_STATUS_SHIPPED: '8',
ORDER_STATUS_COMPLETED: '9',
ORDER_STATUS_EXCHANGE_APPLY: '12',
ORDER_STATUS_EXCHANGE_AGREED: '13',
ORDER_STATUS_EXCHANGE_LOGISTICS: '15',
ORDER_STATUS_EXCHANGE_COMPLETED: '17',
ORDER_STATUS_EXCHANGE_REJECTED: '21',
logisticsDialogVisible: false,
logisticsBasic: null,
@@ -1079,6 +1048,7 @@ export default {
reason: [{ required: true, message: '请输入换货申请原因', trigger: 'blur' }]
},
formMode: 'create',
formDialogKey: 0,
selectedRow: null,
title: '',
open: false,
@@ -1160,7 +1130,7 @@ export default {
},
exchangeApplyDialogSubtitle() {
if (this.exchangeApplyForm && this.exchangeApplyForm.orderNo) {
return `订单编号 ${this.exchangeApplyForm.orderNo} · 填写原因后提交换货申请`
return `订单编号 ${this.exchangeApplyForm.orderNo} · 提交后将生成 HH 前缀的新换货申请`
}
return '填写原因后提交换货申请'
},
@@ -1237,6 +1207,7 @@ export default {
if (!this.tenantId && this.$store.getters.token) {
await this.$store.dispatch('GetInfo').catch(() => {})
}
this.reset()
this.initPage()
},
methods: {
@@ -1312,14 +1283,35 @@ export default {
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_DRAFT || status === this.ORDER_STATUS_REJECTED
},
isExchangeOrder(row) {
if (!row) return false
if (row.orderNo && String(row.orderNo).startsWith('HH')) return true
const status = row.orderStatus != null ? String(row.orderStatus) : ''
return status === this.ORDER_STATUS_EXCHANGE_APPLY
|| status === this.ORDER_STATUS_EXCHANGE_AGREED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED
},
formatDetailPriceTotal(detail, priceKey) {
if (this.isExchangeOrder(detail)) return this.formatDetailLogisticsFee(detail)
return this.formatPriceTotal(detail, priceKey)
},
formatLogisticsFee(row) {
if (!row) return '-'
if (!this.isExchangeOrder(row)) return '-'
const fee = this.parseLogisticsFeeValue(row.logisticsFee)
return fee != null ? fee : '-'
},
formatPriceB(row) {
if (!row) return '-'
if (this.isExchangeOrder(row)) return '-'
if (this.isUnsetPriceStatus(row)) return '-'
if (String(row.orderStatus) === this.ORDER_STATUS_SUBMIT) return '未核算'
return row.priceB != null ? row.priceB : '-'
},
formatProgressiveMultifocalPrice(row) {
if (!row) return '-'
if (this.isExchangeOrder(row)) return '-'
if (Number(row.progressiveMultifocal) !== 1) return '-'
if (this.isUnsetPriceStatus(row)) return '-'
if (String(row.orderStatus) === this.ORDER_STATUS_SUBMIT) return '未核算'
@@ -1370,7 +1362,7 @@ export default {
hasFee = true
}
})
if (!hasFee && logs.length > 0 && detail.logisticsFee != null) {
if (!hasFee && detail.logisticsFee != null) {
const legacyFee = this.parseLogisticsFeeValue(detail.logisticsFee)
if (legacyFee != null) return legacyFee
}
@@ -1380,24 +1372,6 @@ export default {
formatDetailLogisticsFee(detail) {
return this.sumDetailLogisticsFee(detail)
},
formatLogSaleSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null
}
if (log.saleSettleStatus != null && log.saleSettleStatus !== '') {
return log.saleSettleStatus
}
return '0'
},
formatLogPurchaseSettleStatus(log) {
if (!log || log.expressNo == null || String(log.expressNo).trim() === '') {
return null
}
if (log.purchaseSettleStatus != null && log.purchaseSettleStatus !== '') {
return log.purchaseSettleStatus
}
return '0'
},
formatShipDate(time) {
if (!time) {
return '-'
@@ -1623,6 +1597,8 @@ export default {
},
cancel() {
this.open = false
},
handleFormClosed() {
this.reset()
},
handleProgressiveMultifocalChange(value) {
@@ -1680,11 +1656,9 @@ export default {
handleAdd() {
this.reset()
this.formMode = 'create'
this.open = true
this.title = '新增配片单'
this.$nextTick(() => {
this.resetForm('form')
})
this.formDialogKey += 1
this.open = true
},
normalizeOrderForm(form) {
if (!form) {
@@ -1777,6 +1751,7 @@ export default {
}
this.formMode = mode
this.title = title
this.formDialogKey += 1
this.open = true
this.$nextTick(() => {
if (lensId != null && !Number.isNaN(lensId)) {
@@ -1928,17 +1903,24 @@ export default {
},
canViewLogistics(row) {
if (!row || row.orderStatus == null) return false
const status = Number(row.orderStatus)
return status === Number(this.ORDER_STATUS_SHIPPED) || status === 9
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
|| status === this.ORDER_STATUS_COMPLETED
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED
},
canCompleteOrder(row) {
if (!row || row.orderStatus == null) return false
return String(row.orderStatus) === this.ORDER_STATUS_SHIPPED
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_SHIPPED
|| status === this.ORDER_STATUS_EXCHANGE_LOGISTICS
},
canExchangeApplyOrder(row) {
if (!row || row.orderStatus == null) return false
const status = String(row.orderStatus)
return status === this.ORDER_STATUS_COMPLETED || status === this.ORDER_STATUS_EXCHANGE_REJECTED
return status === this.ORDER_STATUS_COMPLETED
|| status === this.ORDER_STATUS_EXCHANGE_COMPLETED
|| status === this.ORDER_STATUS_EXCHANGE_REJECTED
},
canReceiveOrder(row) {
if (!row || row.orderStatus == null) return false
@@ -2033,7 +2015,7 @@ export default {
},
handleExchangeApply(row) {
if (!row || !row.id || !this.canExchangeApplyOrder(row)) {
this.$message.warning('仅已完成或拒绝换货申请状态订单可申请换货')
this.$message.warning('仅已完成、换货完成或拒绝换货申请状态订单可申请换货')
return
}
this.exchangeApplyForm = {
@@ -2057,8 +2039,10 @@ export default {
exchangeApplyPortalOrder({
orderId: this.exchangeApplyForm.orderId,
reason: this.exchangeApplyForm.reason
}).then(() => {
this.$modal.msgSuccess('换货申请已提交')
}).then((res) => {
const newOrder = res && res.data
const newOrderNo = newOrder && newOrder.orderNo ? newOrder.orderNo : ''
this.$modal.msgSuccess(newOrderNo ? `换货申请已提交,新订单号:${newOrderNo}` : '换货申请已提交')
this.exchangeApplyOpen = false
this.getList()
if (this.detailOpen && this.detail.id === this.exchangeApplyForm.orderId) {

View File

@@ -16,7 +16,7 @@ public class SmsProperties
/** 配片订单分配至镜片厂(模板变量 code=订单号) */
private SceneConfig assignOrder = new SceneConfig();
/** 配片订单发货通知(模板变量 code、expressCompany、expressNo */
/** 配片订单发货通知(模板变量 code、expressCompany */
private SceneConfig shipOrder = new SceneConfig();
public String getSignName()

View File

@@ -199,32 +199,6 @@ public class JySysOrderController extends BaseController
rejectDTO.getOrderId(), rejectDTO.getReason().trim(), getUsername()));
}
@PreAuthorize("@ss.hasPermi('jysystem:order:edit')")
@Log(title = "拒绝换货申请订单完成", businessType = BusinessType.UPDATE)
@PutMapping("/exchangeRejectedComplete")
public AjaxResult exchangeRejectedComplete(@RequestBody OrderCloseDTO completeDTO)
{
if (completeDTO == null || completeDTO.getOrderId() == null)
{
return error("订单ID不能为空");
}
return toAjax(jySysOrderService.adminCompleteExchangeRejectedOrder(
completeDTO.getOrderId(), getUsername()));
}
@PreAuthorize("@ss.hasPermi('jysystem:order:edit')")
@Log(title = "批量完成拒绝换货申请订单", businessType = BusinessType.UPDATE)
@PutMapping("/exchangeRejectedCompleteAll")
public AjaxResult exchangeRejectedCompleteAll()
{
int rows = jySysOrderService.adminCompleteAllExchangeRejectedOrders(getUsername());
if (rows <= 0)
{
return success("没有需要更新的订单");
}
return success("已成功更新 " + rows + " 条订单");
}
@PreAuthorize("@ss.hasPermi('jysystem:order:edit')")
@Log(title = "订单状态变更", businessType = BusinessType.UPDATE)
@PutMapping("/changeStatus")

View File

@@ -210,7 +210,7 @@ public class JySysOrderPortalController extends BaseController
{
return error("换货申请原因不能为空");
}
return toAjax(jySysOrderPortalService.exchangeApplyPortalOrder(
return success(jySysOrderPortalService.exchangeApplyPortalOrder(
exchangeDTO.getOrderId(), exchangeDTO.getReason().trim()));
}

View File

@@ -25,12 +25,6 @@ public class JySysOrderStatusLog
private BigDecimal logisticsFee;
/** 应收结算状态0未结算 1已结算 */
private String saleSettleStatus;
/** 应付结算状态0未结算 1已结算 */
private String purchaseSettleStatus;
private String remark;
private String operator;
@@ -98,26 +92,6 @@ public class JySysOrderStatusLog
this.logisticsFee = logisticsFee;
}
public String getSaleSettleStatus()
{
return saleSettleStatus;
}
public void setSaleSettleStatus(String saleSettleStatus)
{
this.saleSettleStatus = saleSettleStatus;
}
public String getPurchaseSettleStatus()
{
return purchaseSettleStatus;
}
public void setPurchaseSettleStatus(String purchaseSettleStatus)
{
this.purchaseSettleStatus = purchaseSettleStatus;
}
public String getRemark()
{
return remark;
@@ -158,8 +132,6 @@ public class JySysOrderStatusLog
.append("expressCompany", getExpressCompany())
.append("expressNo", getExpressNo())
.append("logisticsFee", getLogisticsFee())
.append("saleSettleStatus", getSaleSettleStatus())
.append("purchaseSettleStatus", getPurchaseSettleStatus())
.append("remark", getRemark())
.append("operator", getOperator())
.append("operateTime", getOperateTime())

View File

@@ -28,6 +28,8 @@ public interface JySysOrderMapper extends BaseMapper<JySysOrder>
int countByTenantId(@Param("tenantId") Long tenantId);
int countByOrderNo(@Param("orderNo") String orderNo);
List<JySysOrder> selectCompletedOrdersByYearMonth(@Param("settleYearMonth") String settleYearMonth);
int updatePurchaseSettleStatusByOrderIds(@Param("orderIds") List<Long> orderIds,

View File

@@ -17,10 +17,4 @@ public interface JySysOrderStatusLogMapper
List<JySysOrderStatusLog> selectUnsettledShipLogsByOrderIdAndType(@Param("orderId") Long orderId,
@Param("settlementType") String settlementType);
int updateSaleSettleStatusByIds(@Param("ids") List<Long> ids, @Param("settleStatus") String settleStatus);
int updatePurchaseSettleStatusByIds(@Param("ids") List<Long> ids, @Param("settleStatus") String settleStatus);
int resetShipLogSettleStatusByOrderIds(@Param("orderIds") List<Long> orderIds);
}

View File

@@ -46,7 +46,7 @@ public interface IJySysOrderPortalService
int completePortalOrder(Long orderId);
int exchangeApplyPortalOrder(Long orderId, String reason);
JySysOrder exchangeApplyPortalOrder(Long orderId, String reason);
int receivePortalOrder(Long orderId);

View File

@@ -52,7 +52,7 @@ public interface IJySysOrderService extends IService<JySysOrder>
int brandReceiveExchangeRejectedOrder(Long orderId, Long brandTenantId, String operator);
int brandExchangeApplyOrder(Long orderId, Long brandTenantId, String reason, String operator);
JySysOrder brandExchangeApplyOrder(Long orderId, Long brandTenantId, String reason, String operator);
int adminRejectOrder(Long orderId, String reason, String operator);
@@ -64,10 +64,6 @@ public interface IJySysOrderService extends IService<JySysOrder>
int adminRejectExchangeOrder(Long orderId, String reason, String operator);
int adminCompleteExchangeRejectedOrder(Long orderId, String operator);
int adminCompleteAllExchangeRejectedOrders(String operator);
int brandResubmitOrder(Long orderId, Long brandTenantId, String reason, String operator);
int changeOrderStatus(Long orderId, String orderStatus, String operator);

View File

@@ -14,12 +14,11 @@ public interface SmsNotificationService
void trySendOrderAssignedNotify(String phone, String orderNo);
/**
* 订单发货后,向收件人手机号发送通知(失败不影响主流程)
* 订单发货后发送通知(失败不影响主流程)
*
* @param phone 手机号
* @param phone 手机号(品牌方租户手机号,或收货人手机号)
* @param orderNo 订单号,对应模板变量 code
* @param expressCompany 快递公司,对应模板变量 expressCompany
* @param expressNo 快递单号,对应模板变量 expressNo
*/
void trySendOrderShippedNotify(String phone, String orderNo, String expressCompany, String expressNo);
void trySendOrderShippedNotify(String phone, String orderNo, String expressCompany);
}

View File

@@ -37,6 +37,14 @@ import com.ruoyi.jysystem.vo.FeeSettlementDetailVO;
@Service
public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
{
private static final String ORDER_STATUS_EXCHANGE_APPLY = "12";
private static final String ORDER_STATUS_EXCHANGE_AGREED = "13";
private static final String ORDER_STATUS_EXCHANGE_LOGISTICS = "15";
private static final String ORDER_STATUS_EXCHANGE_COMPLETED = "17";
@Resource
private JySysFeeSettlementMapper feeSettlementMapper;
@@ -130,10 +138,6 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
{
throw new ServiceException("该年月没有已完成状态的订单,无法生成结算单");
}
if (forceRegenerate && exists)
{
resetShipLogSettleStatusForOrders(orders);
}
Map<Long, List<JySysOrder>> brandGroups = new LinkedHashMap<>();
Map<Long, List<JySysOrder>> factoryGroups = new LinkedHashMap<>();
@@ -210,27 +214,9 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
update.setUpdateTime(DateUtils.getNowDate());
int rows = feeSettlementMapper.updateSettleStatus(update);
updateOrderSettleStatusBySettlement(settlement, operator);
updateStatusLogSettleStatusBySettlement(settlement);
return rows;
}
private void updateStatusLogSettleStatusBySettlement(JySysFeeSettlement settlement)
{
List<Long> statusLogIds = collectStatusLogIdsBySettlement(settlement.getId());
if (statusLogIds.isEmpty())
{
return;
}
if (JySysFeeSettlement.TYPE_AP.equals(settlement.getSettlementType()))
{
jySysOrderStatusLogMapper.updatePurchaseSettleStatusByIds(statusLogIds, "1");
}
else if (JySysFeeSettlement.TYPE_AR.equals(settlement.getSettlementType()))
{
jySysOrderStatusLogMapper.updateSaleSettleStatusByIds(statusLogIds, "1");
}
}
private void updateOrderSettleStatusBySettlement(JySysFeeSettlement settlement, String operator)
{
List<JySysFeeSettlementItem> items = feeSettlementItemMapper.selectBySettlementId(settlement.getId());
@@ -314,10 +300,13 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
private JySysFeeSettlementItem buildSettlementItem(Long settlementId, String type, JySysOrder order)
{
BigDecimal lensPrice = JySysFeeSettlement.TYPE_AR.equals(type)
? defaultAmount(order.getPriceC()) : defaultAmount(order.getPriceB());
BigDecimal progressivePrice = Integer.valueOf(1).equals(order.getProgressiveMultifocal())
? defaultAmount(order.getProgressiveMultifocalPrice()) : BigDecimal.ZERO;
boolean exchangeOrder = isExchangeOrder(order);
BigDecimal lensPrice = exchangeOrder ? BigDecimal.ZERO
: (JySysFeeSettlement.TYPE_AR.equals(type)
? defaultAmount(order.getPriceC()) : defaultAmount(order.getPriceB()));
BigDecimal progressivePrice = exchangeOrder ? BigDecimal.ZERO
: (Integer.valueOf(1).equals(order.getProgressiveMultifocal())
? defaultAmount(order.getProgressiveMultifocalPrice()) : BigDecimal.ZERO);
List<JySysOrderStatusLog> shipLogs = jySysOrderStatusLogMapper
.selectUnsettledShipLogsByOrderIdAndType(order.getId(), type);
@@ -374,7 +363,6 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
{
continue;
}
revertLogSettleStatusBySettlement(settlement);
if ("1".equals(settlement.getSettleStatus()))
{
revertOrderSettleStatusBySettlement(settlement);
@@ -392,24 +380,6 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
}
}
/** 删除结算单时回滚关联发货日志的结算状态,便于重新生成时再次纳入物流费用 */
private void revertLogSettleStatusBySettlement(JySysFeeSettlement settlement)
{
List<Long> statusLogIds = collectStatusLogIdsBySettlement(settlement.getId());
if (statusLogIds.isEmpty())
{
return;
}
if (JySysFeeSettlement.TYPE_AP.equals(settlement.getSettlementType()))
{
jySysOrderStatusLogMapper.updatePurchaseSettleStatusByIds(statusLogIds, "0");
}
else if (JySysFeeSettlement.TYPE_AR.equals(settlement.getSettlementType()))
{
jySysOrderStatusLogMapper.updateSaleSettleStatusByIds(statusLogIds, "0");
}
}
private void revertOrderSettleStatusBySettlement(JySysFeeSettlement settlement)
{
List<JySysFeeSettlementItem> items = feeSettlementItemMapper.selectBySettlementId(settlement.getId());
@@ -433,38 +403,6 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
}
}
private void resetShipLogSettleStatusForOrders(List<JySysOrder> orders)
{
if (orders == null || orders.isEmpty())
{
return;
}
List<Long> orderIds = orders.stream()
.map(JySysOrder::getId)
.filter(orderId -> orderId != null)
.distinct()
.collect(Collectors.toList());
if (!orderIds.isEmpty())
{
jySysOrderStatusLogMapper.resetShipLogSettleStatusByOrderIds(orderIds);
}
}
private List<Long> collectStatusLogIdsBySettlement(Long settlementId)
{
List<JySysFeeSettlementItem> items = feeSettlementItemMapper.selectBySettlementId(settlementId);
if (items == null || items.isEmpty())
{
return new ArrayList<>();
}
List<Long> itemIds = items.stream().map(JySysFeeSettlementItem::getId).collect(Collectors.toList());
return feeSettlementLogisticsMapper.selectBySettlementItemIds(itemIds).stream()
.map(JySysFeeSettlementLogistics::getStatusLogId)
.filter(statusLogId -> statusLogId != null)
.distinct()
.collect(Collectors.toList());
}
private String nextSettlementNo(String type)
{
String datePart = new SimpleDateFormat("yyyyMMdd").format(new Date());
@@ -496,6 +434,23 @@ public class JySysFeeSettlementServiceImpl implements IJySysFeeSettlementService
return value != null ? value : BigDecimal.ZERO;
}
private boolean isExchangeOrder(JySysOrder order)
{
if (order == null)
{
return false;
}
if (StringUtils.isNotEmpty(order.getOrderNo()) && order.getOrderNo().startsWith("HH"))
{
return true;
}
String status = order.getOrderStatus();
return ORDER_STATUS_EXCHANGE_APPLY.equals(status)
|| ORDER_STATUS_EXCHANGE_AGREED.equals(status)
|| ORDER_STATUS_EXCHANGE_LOGISTICS.equals(status)
|| ORDER_STATUS_EXCHANGE_COMPLETED.equals(status);
}
@Override
public byte[] exportPdf(Long id)
{

View File

@@ -229,7 +229,7 @@ public class JySysOrderPortalServiceImpl implements IJySysOrderPortalService
}
@Override
public int exchangeApplyPortalOrder(Long orderId, String reason)
public JySysOrder exchangeApplyPortalOrder(Long orderId, String reason)
{
JySysTenant tenant = requireBrandTenant();
return jySysOrderService.brandExchangeApplyOrder(

View File

@@ -59,6 +59,10 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
private static final String ORDER_STATUS_EXCHANGE_AGREED = "13";
private static final String ORDER_STATUS_EXCHANGE_LOGISTICS = "15";
private static final String ORDER_STATUS_EXCHANGE_COMPLETED = "17";
private static final String ORDER_STATUS_EXCHANGE_REJECTED = "21";
private static final String ORDER_STATUS_CANCELLED = "18";
@@ -347,7 +351,7 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
throw new ServiceException("物流费用不能小于0");
}
saveStatusLog(orderId, ORDER_STATUS_SHIPPED, operator, expressCompany, expressNo, null, logisticsFee);
saveStatusLog(orderId, resolveShipStatus(order), operator, expressCompany, expressNo, null, logisticsFee);
BigDecimal totalLogisticsFee = jySysOrderStatusLogMapper.sumLogisticsFeeByOrderId(orderId);
if (totalLogisticsFee == null)
{
@@ -362,7 +366,7 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(totalLogisticsFee);
update.setOrderStatus(ORDER_STATUS_SHIPPED);
update.setOrderStatus(resolveShipStatus(order));
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
@@ -383,12 +387,13 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(order.getLogisticsFee());
update.setOrderStatus(ORDER_STATUS_COMPLETED);
String completeStatus = resolveCompleteStatus(order);
update.setOrderStatus(completeStatus);
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
int rows = jySysOrderMapper.updateJySysOrder(update);
saveStatusLog(orderId, ORDER_STATUS_COMPLETED, operator, null, null, null);
saveStatusLog(orderId, completeStatus, operator, null, null, null);
return rows;
}
@@ -406,12 +411,13 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(order.getLogisticsFee());
update.setOrderStatus(ORDER_STATUS_COMPLETED);
String completeStatus = resolveCompleteStatus(order);
update.setOrderStatus(completeStatus);
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
int rows = jySysOrderMapper.updateJySysOrder(update);
saveStatusLog(orderId, ORDER_STATUS_COMPLETED, operator, null, null, null);
saveStatusLog(orderId, completeStatus, operator, null, null, null);
return rows;
}
@@ -440,29 +446,19 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
@Override
@Transactional(rollbackFor = Exception.class)
public int brandExchangeApplyOrder(Long orderId, Long brandTenantId, String reason, String operator)
public JySysOrder brandExchangeApplyOrder(Long orderId, Long brandTenantId, String reason, String operator)
{
JySysOrder order = requireBrandExchangeAppliableOrder(orderId, brandTenantId);
requireBrandExchangeAppliableOrder(orderId, brandTenantId);
if (StringUtils.isEmpty(reason))
{
throw new ServiceException("换货申请原因不能为空");
}
JySysOrder update = new JySysOrder();
update.setId(orderId);
update.setBrandTenantId(order.getBrandTenantId());
update.setLensId(order.getLensId());
update.setProductId(order.getProductId());
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(order.getLogisticsFee());
update.setOrderStatus(ORDER_STATUS_EXCHANGE_APPLY);
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
int rows = jySysOrderMapper.updateJySysOrder(update);
saveStatusLog(orderId, ORDER_STATUS_EXCHANGE_APPLY, operator, null, null, reason);
return rows;
JySysOrder source = selectJySysOrderById(orderId);
if (source == null)
{
throw new ServiceException("订单不存在");
}
return copyOrderForExchangeApply(source, reason, operator);
}
@Override
@@ -557,11 +553,13 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
{
throw new ServiceException("订单不存在");
}
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus()))
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus())
&& !ORDER_STATUS_EXCHANGE_LOGISTICS.equals(order.getOrderStatus()))
{
throw new ServiceException("仅已发货状态的订单可完成");
throw new ServiceException("仅已发货或换货物流状态的订单可完成");
}
String completeStatus = resolveCompleteStatus(order);
JySysOrder update = new JySysOrder();
update.setId(orderId);
update.setBrandTenantId(order.getBrandTenantId());
@@ -570,12 +568,12 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(order.getLogisticsFee());
update.setOrderStatus(ORDER_STATUS_COMPLETED);
update.setOrderStatus(completeStatus);
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
int rows = jySysOrderMapper.updateJySysOrder(update);
saveStatusLog(orderId, ORDER_STATUS_COMPLETED, operator, null, null, null);
saveStatusLog(orderId, completeStatus, operator, null, null, null);
return rows;
}
@@ -629,33 +627,6 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
return rows;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int adminCompleteExchangeRejectedOrder(Long orderId, String operator)
{
return completeExchangeRejectedToCompleted(orderId, operator);
}
@Override
@Transactional(rollbackFor = Exception.class)
public int adminCompleteAllExchangeRejectedOrders(String operator)
{
JySysOrder query = new JySysOrder();
query.setOrderStatus(ORDER_STATUS_EXCHANGE_REJECTED);
List<JySysOrder> orderList = jySysOrderMapper.selectJySysOrderList(query);
if (orderList == null || orderList.isEmpty())
{
return 0;
}
int count = 0;
for (JySysOrder order : orderList)
{
completeExchangeRejectedToCompleted(order.getId(), operator);
count++;
}
return count;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int brandResubmitOrder(Long orderId, Long brandTenantId, String reason, String operator)
@@ -801,9 +772,10 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
private JySysOrder requireFactoryCompletableOrder(Long orderId, Long lensFactoryTenantId)
{
JySysOrder order = requireFactoryOwnedOrder(orderId, lensFactoryTenantId);
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus()))
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus())
&& !ORDER_STATUS_EXCHANGE_LOGISTICS.equals(order.getOrderStatus()))
{
throw new ServiceException("仅已发货状态的订单可完成");
throw new ServiceException("仅已发货或换货物流状态的订单可完成");
}
return order;
}
@@ -827,9 +799,10 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
{
throw new ServiceException("无权操作该订单");
}
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus()))
if (!ORDER_STATUS_SHIPPED.equals(order.getOrderStatus())
&& !ORDER_STATUS_EXCHANGE_LOGISTICS.equals(order.getOrderStatus()))
{
throw new ServiceException("仅已发货状态的订单可完成");
throw new ServiceException("仅已发货或换货物流状态的订单可完成");
}
return order;
}
@@ -880,46 +853,14 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
throw new ServiceException("无权操作该订单");
}
if (!ORDER_STATUS_COMPLETED.equals(order.getOrderStatus())
&& !ORDER_STATUS_EXCHANGE_COMPLETED.equals(order.getOrderStatus())
&& !ORDER_STATUS_EXCHANGE_REJECTED.equals(order.getOrderStatus()))
{
throw new ServiceException("仅已完成或拒绝换货申请状态的订单可申请换货");
throw new ServiceException("仅已完成、换货完成或拒绝换货申请状态的订单可申请换货");
}
return order;
}
private int completeExchangeRejectedToCompleted(Long orderId, String operator)
{
if (orderId == null)
{
throw new ServiceException("订单ID不能为空");
}
JySysOrder order = jySysOrderMapper.selectJySysOrderById(orderId);
if (order == null)
{
throw new ServiceException("订单不存在");
}
if (!ORDER_STATUS_EXCHANGE_REJECTED.equals(order.getOrderStatus()))
{
throw new ServiceException("仅拒绝换货申请状态的订单可完成");
}
JySysOrder update = new JySysOrder();
update.setId(orderId);
update.setBrandTenantId(order.getBrandTenantId());
update.setLensId(order.getLensId());
update.setProductId(order.getProductId());
update.setAttachment(order.getAttachment());
update.setLensFactoryTenantId(order.getLensFactoryTenantId());
update.setLogisticsFee(order.getLogisticsFee());
update.setOrderStatus(ORDER_STATUS_COMPLETED);
update.setUpdateBy(operator);
update.setUpdateTime(DateUtils.getNowDate());
int rows = jySysOrderMapper.updateJySysOrder(update);
saveStatusLog(orderId, ORDER_STATUS_COMPLETED, operator, null, null, null);
return rows;
}
private JySysOrder requireAdminExchangeAppliableOrder(Long orderId)
{
if (orderId == null)
@@ -1126,6 +1067,45 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
}
}
private String resolveShipStatus(JySysOrder order)
{
if (order != null && isExchangeOrder(order.getId()))
{
return ORDER_STATUS_EXCHANGE_LOGISTICS;
}
return ORDER_STATUS_SHIPPED;
}
private String resolveCompleteStatus(JySysOrder order)
{
if (order != null && ORDER_STATUS_EXCHANGE_LOGISTICS.equals(order.getOrderStatus()))
{
return ORDER_STATUS_EXCHANGE_COMPLETED;
}
return ORDER_STATUS_COMPLETED;
}
private boolean isExchangeOrder(Long orderId)
{
if (orderId == null)
{
return false;
}
List<JySysOrderStatusLog> logs = jySysOrderStatusLogMapper.selectJySysOrderStatusLogByOrderId(orderId);
if (logs == null || logs.isEmpty())
{
return false;
}
for (JySysOrderStatusLog log : logs)
{
if (log != null && ORDER_STATUS_EXCHANGE_APPLY.equals(log.getOrderStatus()))
{
return true;
}
}
return false;
}
private void saveOptometryList(JySysOrder jySysOrder)
{
if (jySysOrder.getId() == null)
@@ -1200,12 +1180,6 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
statusLog.setExpressCompany(expressCompany);
statusLog.setExpressNo(expressNo);
statusLog.setLogisticsFee(logisticsFee);
if (ORDER_STATUS_SHIPPED.equals(orderStatus)
&& StringUtils.isNotEmpty(expressNo))
{
statusLog.setSaleSettleStatus("0");
statusLog.setPurchaseSettleStatus("0");
}
statusLog.setRemark(remark);
statusLog.setOperator(operator);
statusLog.setOperateTime(DateUtils.getNowDate());
@@ -1219,4 +1193,94 @@ public class JySysOrderServiceImpl extends ServiceImpl<JySysOrderMapper, JySysOr
int randomPart = ThreadLocalRandom.current().nextInt(1000, 10000);
return "JY" + timePart + randomPart;
}
private JySysOrder copyOrderForExchangeApply(JySysOrder source, String reason, String operator)
{
Date now = DateUtils.getNowDate();
JySysOrder newOrder = new JySysOrder();
newOrder.setOrderNo(buildExchangeOrderNo(source.getOrderNo()));
newOrder.setBrandTenantId(source.getBrandTenantId());
newOrder.setLensFactoryTenantId(source.getLensFactoryTenantId());
newOrder.setProductId(source.getProductId());
newOrder.setLensId(source.getLensId());
newOrder.setPriceB(source.getPriceB());
newOrder.setPriceC(source.getPriceC());
newOrder.setLogisticsFee(BigDecimal.ZERO);
newOrder.setProgressiveMultifocal(source.getProgressiveMultifocal());
newOrder.setProgressiveMultifocalPrice(source.getProgressiveMultifocalPrice());
newOrder.setOrderStatus(ORDER_STATUS_EXCHANGE_APPLY);
newOrder.setPurchaseSettleStatus("0");
newOrder.setSaleSettleStatus("0");
newOrder.setReceiverName(source.getReceiverName());
newOrder.setReceiverPhone(source.getReceiverPhone());
newOrder.setReceiverAddress(source.getReceiverAddress());
newOrder.setAttachment(source.getAttachment());
newOrder.setRemark(source.getRemark());
newOrder.setDelFlag(0);
newOrder.setCreateBy(operator);
newOrder.setUpdateBy(operator);
newOrder.setCreateTime(now);
newOrder.setUpdateTime(now);
newOrder.setOptometryList(copyOptometryList(source.getOptometryList()));
fillDefaultValue(newOrder);
jySysOrderMapper.insertJySysOrder(newOrder);
saveOptometryList(newOrder);
saveStatusLog(newOrder.getId(), ORDER_STATUS_EXCHANGE_APPLY, operator, null, null, reason);
return selectJySysOrderById(newOrder.getId());
}
private List<JySysOrderOptometry> copyOptometryList(List<JySysOrderOptometry> sourceList)
{
List<JySysOrderOptometry> copiedList = new ArrayList<>();
if (sourceList == null || sourceList.isEmpty())
{
return copiedList;
}
for (JySysOrderOptometry source : sourceList)
{
if (source == null || StringUtils.isEmpty(source.getEyeSide()))
{
continue;
}
JySysOrderOptometry copy = new JySysOrderOptometry();
copy.setEyeSide(source.getEyeSide());
copy.setSphereS(source.getSphereS());
copy.setCylinderC(source.getCylinderC());
copy.setAxisA(source.getAxisA());
copy.setPd(source.getPd());
copy.setDualPd(source.getDualPd());
copy.setPdType(source.getPdType());
copy.setPupilHeight(source.getPupilHeight());
copy.setDistanceVa(source.getDistanceVa());
copy.setNearAdd(source.getNearAdd());
copiedList.add(copy);
}
return copiedList;
}
private String buildExchangeOrderNo(String sourceOrderNo)
{
String numericPart = StringUtils.isEmpty(sourceOrderNo)
? new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
+ ThreadLocalRandom.current().nextInt(1000, 10000)
: sourceOrderNo.replaceAll("\\D", "");
if (StringUtils.isEmpty(numericPart))
{
numericPart = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
+ ThreadLocalRandom.current().nextInt(1000, 10000);
}
String orderNo = "HH" + numericPart;
int retry = 0;
while (jySysOrderMapper.countByOrderNo(orderNo) > 0 && retry < 10)
{
orderNo = "HH" + numericPart + ThreadLocalRandom.current().nextInt(1000, 10000);
retry++;
}
if (jySysOrderMapper.countByOrderNo(orderNo) > 0)
{
throw new ServiceException("生成换货订单号失败,请稍后重试");
}
return orderNo;
}
}

View File

@@ -2,6 +2,8 @@ package com.ruoyi.jysystem.service.impl;
import java.util.List;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
@@ -23,12 +25,16 @@ import com.ruoyi.jysystem.utils.TenantTypeHelper;
@Service
public class JySysTenantMessageServiceImpl implements IJySysTenantMessageService
{
private static final Logger log = LoggerFactory.getLogger(JySysTenantMessageServiceImpl.class);
private static final String ORDER_STATUS_DRAFT = "1";
private static final String ORDER_STATUS_ASSIGNED = "3";
private static final String ORDER_STATUS_SHIPPED = "8";
private static final String ORDER_STATUS_EXCHANGE_LOGISTICS = "15";
@Resource
private JySysTenantMessageMapper jySysTenantMessageMapper;
@@ -102,17 +108,30 @@ public class JySysTenantMessageServiceImpl implements IJySysTenantMessageService
}
insertMessage(order.getBrandTenantId(), order.getId(), orderNo,
JySysTenantMessage.TYPE_STATUS_CHANGE, "订单状态变更", content, orderStatus);
if (ORDER_STATUS_SHIPPED.equals(orderStatus))
if (ORDER_STATUS_SHIPPED.equals(orderStatus)
|| ORDER_STATUS_EXCHANGE_LOGISTICS.equals(orderStatus))
{
String smsPhone = StringUtils.isNotEmpty(order.getReceiverPhone())
? order.getReceiverPhone()
: brandTenant.getPhone();
log.info("[发货短信] 触发检查: orderId={}, orderNo={}, orderStatus={}, expressCompany={}, brandTenantId={}, brandPhone={}, receiverPhone={}",
orderId, orderNo, orderStatus, expressCompany, brandTenant.getId(), brandTenant.getPhone(), order.getReceiverPhone());
String smsPhone = resolveShipNotifyPhone(brandTenant.getPhone(), order.getReceiverPhone());
if (StringUtils.isNotEmpty(smsPhone))
{
smsNotificationService.trySendOrderShippedNotify(smsPhone, orderNo, expressCompany, expressNo);
log.info("[发货短信] 准备发送: orderNo={}, smsPhone={}, expressCompany={}", orderNo, smsPhone, expressCompany);
smsNotificationService.trySendOrderShippedNotify(
smsPhone, orderNo, expressCompany);
}
else
{
log.warn("[发货短信] 跳过: 无有效手机号, orderNo={}, brandPhone={}, receiverPhone={}",
orderNo, brandTenant.getPhone(), order.getReceiverPhone());
}
}
}
else
{
log.warn("[发货短信] 跳过: 品牌方租户无效, orderId={}, brandTenantId={}, tenantType={}",
orderId, order.getBrandTenantId(), brandTenant != null ? brandTenant.getTenantType() : null);
}
}
if (order.getLensFactoryTenantId() != null)
@@ -170,4 +189,41 @@ public class JySysTenantMessageServiceImpl implements IJySysTenantMessageService
}
return tenant;
}
private String resolveShipNotifyPhone(String brandPhone, String receiverPhone)
{
if (isValidMobile(brandPhone))
{
return normalizeMobile(brandPhone);
}
if (isValidMobile(receiverPhone))
{
return normalizeMobile(receiverPhone);
}
return null;
}
private boolean isValidMobile(String phone)
{
return normalizeMobile(phone) != null;
}
private String normalizeMobile(String phone)
{
if (StringUtils.isEmpty(phone))
{
return null;
}
String digits = phone.replaceAll("\\D", "");
if (digits.length() >= 11)
{
String mobile = digits.substring(digits.length() - 11);
if (mobile.matches("^1[3-9]\\d{9}$"))
{
return mobile;
}
}
String trimmed = phone.trim();
return trimmed.matches("^1[3-9]\\d{9}$") ? trimmed : null;
}
}

View File

@@ -35,56 +35,67 @@ public class SmsNotificationServiceImpl implements SmsNotificationService
}
@Override
public void trySendOrderShippedNotify(String phone, String orderNo, String expressCompany, String expressNo)
public void trySendOrderShippedNotify(String phone, String orderNo, String expressCompany)
{
Map<String, String> params = new HashMap<>(3);
Map<String, String> params = new HashMap<>(2);
params.put("code", nullToEmpty(orderNo));
params.put("expressCompany", nullToEmpty(expressCompany));
params.put("expressNo", nullToEmpty(expressNo));
trySendScene("配片订单发货", smsProperties.getShipOrder(), phone, params);
}
private void trySendScene(String sceneLabel, SmsProperties.SceneConfig scene, String phone, Map<String, String> templateParams)
{
if (scene == null || !scene.isEnabled())
if (scene == null)
{
log.warn("[发货短信] 跳过: {}场景配置为空", sceneLabel);
return;
}
if (!scene.isEnabled())
{
log.warn("[发货短信] 跳过: {}短信未启用, enabled=false", sceneLabel);
return;
}
if (StringUtils.isEmpty(phone))
{
log.warn("[发货短信] 跳过: {}手机号为空", sceneLabel);
return;
}
String templateCode = StringUtils.isNotEmpty(scene.getTemplate()) ? scene.getTemplate().trim() : null;
if (StringUtils.isEmpty(templateCode))
{
log.warn("未配置{}短信模板请在 application.yml 的 sms.{} 中填写 template",
log.warn("[发货短信] 跳过: 未配置{}短信模板, 请在 application.yml 的 sms.{} 中填写 template",
sceneLabel, sceneLabel.contains("分配") ? "assign-order" : "ship-order");
return;
}
String mobile = phone.trim();
if (!MOBILE_PATTERN.matcher(mobile).matches())
String mobile = normalizeMobile(phone);
if (mobile == null)
{
log.warn("{}短信手机号格式无效,跳过通知: {}", sceneLabel, phone);
log.warn("[发货短信] 跳过: {}手机号格式无效, rawPhone={}", sceneLabel, phone);
return;
}
String signName = smsProperties.getSignName();
String templateParam = JSON.toJSONString(templateParams);
log.info("[发货短信] 调用阿里云: scene={}, phone={}, signName={}, template={}, params={}",
sceneLabel, mobile, signName, templateCode, templateParam);
try
{
String templateParam = JSON.toJSONString(templateParams);
Map<String, Object> result = SmsUtils.sendNotifyMsg(mobile, smsProperties.getSignName(),
templateCode, templateParam);
Map<String, Object> result = SmsUtils.sendNotifyMsg(mobile, signName, templateCode, templateParam);
Integer statusCode = (Integer) result.get("statusCode");
String bodyCode = (String) result.get("bodyCode");
String bodyMessage = (String) result.get("bodyMessage");
String bizId = (String) result.get("bizId");
String requestId = (String) result.get("requestId");
if (statusCode == null || statusCode != 200 || !"OK".equalsIgnoreCase(bodyCode))
{
log.warn("{}短信发送失败: phone={}, template={}, params={}, statusCode={}, bodyCode={}",
sceneLabel, mobile, templateCode, templateParam, statusCode, bodyCode);
log.warn("[发货短信] 发送失败: scene={}, phone={}, template={}, params={}, statusCode={}, bodyCode={}, bodyMessage={}, bizId={}, requestId={}",
sceneLabel, mobile, templateCode, templateParam, statusCode, bodyCode, bodyMessage, bizId, requestId);
return;
}
log.info("{}短信已发送: {}", sceneLabel, mobile);
log.info("[发货短信] 发送成功: scene={}, phone={}, bizId={}, requestId={}", sceneLabel, mobile, bizId, requestId);
}
catch (Exception e)
{
log.warn("{}短信发送异常: phone={}, err={}", sceneLabel, mobile, e.getMessage());
log.warn("[发货短信] 发送异常: scene={}, phone={}, err={}", sceneLabel, mobile, e.getMessage(), e);
}
}
@@ -92,4 +103,22 @@ public class SmsNotificationServiceImpl implements SmsNotificationService
{
return value != null ? value : "";
}
private String normalizeMobile(String phone)
{
if (StringUtils.isEmpty(phone))
{
return null;
}
String digits = phone.replaceAll("\\D", "");
if (digits.length() >= 11)
{
String mobile = digits.substring(digits.length() - 11);
if (MOBILE_PATTERN.matcher(mobile).matches())
{
return mobile;
}
}
return MOBILE_PATTERN.matcher(phone.trim()).matches() ? phone.trim() : null;
}
}

View File

@@ -185,6 +185,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
and (brand_tenant_id = #{tenantId} or lens_factory_tenant_id = #{tenantId})
</select>
<select id="countByOrderNo" resultType="int">
select count(1)
from jy_sys_order
where del_flag = '0'
and order_no = #{orderNo}
</select>
<select id="selectCompletedOrdersByYearMonth" resultMap="JySysOrderResult">
select o.id, o.order_no, o.brand_tenant_id, bt.name as brand_tenant_name,
o.lens_factory_tenant_id, lf.name as lens_factory_tenant_name,
@@ -197,11 +204,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
left join jy_sys_tenant bt on o.brand_tenant_id = bt.id
left join jy_sys_tenant lf on o.lens_factory_tenant_id = lf.id
where o.del_flag = '0'
and o.order_status = '9'
and o.order_status in ('9', '17')
and exists (
select 1 from jy_sys_order_status_log sl
where sl.order_id = o.id
and sl.order_status = '9'
and sl.order_status in ('9', '17')
and DATE_FORMAT(sl.operate_time, '%Y-%m') = #{settleYearMonth}
)
order by o.id asc

View File

@@ -11,8 +11,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="expressCompany" column="express_company" />
<result property="expressNo" column="express_no" />
<result property="logisticsFee" column="logistics_fee" />
<result property="saleSettleStatus" column="sale_settle_status" />
<result property="purchaseSettleStatus" column="purchase_settle_status" />
<result property="remark" column="remark" />
<result property="operator" column="operator" />
<result property="operateTime" column="operate_time" />
@@ -20,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectJySysOrderStatusLogByOrderId" parameterType="Long" resultMap="JySysOrderStatusLogResult">
select id, order_id, order_status, express_company, express_no, logistics_fee,
sale_settle_status, purchase_settle_status, remark, operator, operate_time
remark, operator, operate_time
from jy_sys_order_status_log
where order_id = #{orderId}
order by operate_time desc, id desc
@@ -43,8 +41,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="expressCompany != null">express_company,</if>
<if test="expressNo != null">express_no,</if>
<if test="logisticsFee != null">logistics_fee,</if>
<if test="saleSettleStatus != null">sale_settle_status,</if>
<if test="purchaseSettleStatus != null">purchase_settle_status,</if>
<if test="remark != null">remark,</if>
<if test="operator != null">operator,</if>
<if test="operateTime != null">operate_time,</if>
@@ -55,8 +51,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="expressCompany != null">#{expressCompany},</if>
<if test="expressNo != null">#{expressNo},</if>
<if test="logisticsFee != null">#{logisticsFee},</if>
<if test="saleSettleStatus != null">#{saleSettleStatus},</if>
<if test="purchaseSettleStatus != null">#{purchaseSettleStatus},</if>
<if test="remark != null">#{remark},</if>
<if test="operator != null">#{operator},</if>
<if test="operateTime != null">#{operateTime},</if>
@@ -64,52 +58,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</insert>
<select id="selectUnsettledShipLogsByOrderIdAndType" resultMap="JySysOrderStatusLogResult">
select id, order_id, order_status, express_company, express_no, logistics_fee,
sale_settle_status, purchase_settle_status, remark, operator, operate_time
from jy_sys_order_status_log
where order_id = #{orderId}
and order_status = '8'
and express_no is not null
and TRIM(express_no) != ''
<choose>
<when test="settlementType == 'AR'">
and (sale_settle_status is null or sale_settle_status = '0')
</when>
<when test="settlementType == 'AP'">
and (purchase_settle_status is null or purchase_settle_status = '0')
</when>
</choose>
order by operate_time asc, id asc
select l.id, l.order_id, l.order_status, l.express_company, l.express_no, l.logistics_fee,
l.remark, l.operator, l.operate_time
from jy_sys_order_status_log l
where l.order_id = #{orderId}
and l.order_status in ('8', '15')
and l.express_no is not null
and TRIM(l.express_no) != ''
and l.id not in (
select fl.status_log_id
from jy_sys_fee_settlement_logistics fl
inner join jy_sys_fee_settlement_item fi on fl.settlement_item_id = fi.id
inner join jy_sys_fee_settlement fs on fi.settlement_id = fs.id
where fl.status_log_id is not null
and fs.settlement_type = #{settlementType}
)
order by l.operate_time asc, l.id asc
</select>
<update id="updateSaleSettleStatusByIds">
update jy_sys_order_status_log
set sale_settle_status = #{settleStatus}
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
<update id="updatePurchaseSettleStatusByIds">
update jy_sys_order_status_log
set purchase_settle_status = #{settleStatus}
where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</update>
<update id="resetShipLogSettleStatusByOrderIds">
update jy_sys_order_status_log
set sale_settle_status = '0',
purchase_settle_status = '0'
where order_id in
<foreach collection="orderIds" item="orderId" open="(" separator="," close=")">
#{orderId}
</foreach>
and order_status = '8'
and express_no is not null
and TRIM(express_no) != ''
</update>
</mapper>

View File

@@ -51,7 +51,7 @@ INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value
SELECT 166, 14, '退货物流', '14', 'jy_order_status', NULL, 'primary', 'N', '0', 'admin', NOW(), NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_dict_data` WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '14');
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
SELECT 167, 15, '换货已发货', '15', 'jy_order_status', NULL, 'primary', 'N', '0', 'admin', NOW(), NULL
SELECT 167, 15, '换货物流', '15', 'jy_order_status', NULL, 'primary', 'N', '0', 'admin', NOW(), NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_dict_data` WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '15');
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
SELECT 168, 16, '退货完成', '16', 'jy_order_status', NULL, 'success', 'N', '0', 'admin', NOW(), NULL

View File

@@ -0,0 +1,16 @@
-- 订单状态字典:恢复/确保换货物流、换货完成标签
UPDATE `sys_dict_data`
SET `dict_label` = '换货物流'
WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '15';
UPDATE `sys_dict_data`
SET `dict_label` = '换货完成'
WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '17';
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
SELECT 167, 15, '换货物流', '15', 'jy_order_status', NULL, 'primary', 'N', '0', 'admin', NOW(), NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_dict_data` WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '15');
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `remark`)
SELECT 169, 17, '换货完成', '17', 'jy_order_status', NULL, 'success', 'N', '0', 'admin', NOW(), NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_dict_data` WHERE `dict_type` = 'jy_order_status' AND `dict_value` = '17');

View File

@@ -0,0 +1,4 @@
-- 订单状态日志:移除物流应收/应付结算状态字段(改由费用结算单物流明细关联发货日志)
ALTER TABLE `jy_sys_order_status_log`
DROP COLUMN `sale_settle_status`,
DROP COLUMN `purchase_settle_status`;

View File

@@ -3,16 +3,16 @@ package com.ruoyi.common.utils;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.tea.*;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import static com.aliyun.teautil.Common.assertAsString;
public class SmsUtils {
private static final Logger log = LoggerFactory.getLogger(SmsUtils.class);
public static Client createClient() throws Exception {
Config config = new Config()
// 配置 AccessKey ID请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID。
@@ -43,6 +43,8 @@ public class SmsUtils {
*/
public static Map<String, Object> sendNotifyMsg(String phone, String signName, String templateCode, String templateParam) throws Exception {
HashMap<String, Object> sendSmsResponseMap = new HashMap<>();
log.info("[发货短信] SmsUtils 请求: phone={}, signName={}, templateCode={}, templateParam={}",
phone, signName, templateCode, templateParam);
try {
Client client = SmsUtils.createClient();
SendSmsRequest sendSmsRequest = new SendSmsRequest()
@@ -54,19 +56,26 @@ public class SmsUtils {
SendSmsResponse sendSmsResponse = client.sendSmsWithOptions(sendSmsRequest, new RuntimeOptions());
Integer statusCode = sendSmsResponse.getStatusCode();
String responseCode = sendSmsResponse.getBody().getCode();
String responseCode = sendSmsResponse.getBody() != null ? sendSmsResponse.getBody().getCode() : null;
String responseMessage = sendSmsResponse.getBody() != null ? sendSmsResponse.getBody().getMessage() : null;
String bizId = sendSmsResponse.getBody() != null ? sendSmsResponse.getBody().getBizId() : null;
String requestId = sendSmsResponse.getBody() != null ? sendSmsResponse.getBody().getRequestId() : null;
sendSmsResponseMap.put("statusCode", statusCode);
sendSmsResponseMap.put("bodyCode", responseCode);
} catch (TeaException error) {
System.out.println(error.getMessage());
System.out.println(error.getData().get("Recommend"));
assertAsString(error.message);
sendSmsResponseMap.put("bodyMessage", responseMessage);
sendSmsResponseMap.put("bizId", bizId);
sendSmsResponseMap.put("requestId", requestId);
log.info("[发货短信] SmsUtils 响应: phone={}, statusCode={}, bodyCode={}, bodyMessage={}, bizId={}, requestId={}",
phone, statusCode, responseCode, responseMessage, bizId, requestId);
} catch (com.aliyun.tea.TeaException error) {
log.warn("[发货短信] SmsUtils TeaException: phone={}, code={}, message={}",
phone, error.getCode(), error.getMessage());
sendSmsResponseMap.put("bodyCode", error.getCode());
sendSmsResponseMap.put("bodyMessage", error.getMessage());
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
System.out.println(error.getMessage());
System.out.println("诊断地址" + error.getData().get("Recommend"));
assertAsString(error.message);
log.warn("[发货短信] SmsUtils 异常: phone={}, err={}", phone, _error.getMessage(), _error);
sendSmsResponseMap.put("bodyMessage", _error.getMessage());
}
return sendSmsResponseMap;
}