订单异议问题修复,跟进合同优化
This commit is contained in:
@@ -52,6 +52,11 @@ public class GearReturnExchange extends BaseEntity {
|
||||
* 涉及金额
|
||||
*/
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 销售员ID
|
||||
*/
|
||||
private Long salesmanId;
|
||||
/**
|
||||
* 删除标志(0=正常,1=已删除)
|
||||
*/
|
||||
|
||||
@@ -58,6 +58,11 @@ public class GearReturnExchangeBo extends BaseEntity {
|
||||
*/
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 销售员ID
|
||||
*/
|
||||
private Long salesmanId;
|
||||
|
||||
//订单id
|
||||
private Long orderId;
|
||||
|
||||
|
||||
@@ -41,6 +41,16 @@ public class GearReturnExchangeVo {
|
||||
@ExcelProperty(value = "订单ID")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 销售员ID
|
||||
*/
|
||||
private Long salesmanId;
|
||||
|
||||
/**
|
||||
* 销售员姓名
|
||||
*/
|
||||
private String salesmanName;
|
||||
|
||||
/**
|
||||
* 客户ID
|
||||
*/
|
||||
|
||||
@@ -12,7 +12,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.gear.oa.domain.bo.GearReturnExchangeBo;
|
||||
import com.gear.oa.domain.vo.GearReturnExchangeVo;
|
||||
import com.gear.oa.domain.GearOrder;
|
||||
import com.gear.oa.domain.GearOrderDetail;
|
||||
import com.gear.oa.domain.GearReturnExchange;
|
||||
import com.gear.oa.mapper.GearOrderDetailMapper;
|
||||
import com.gear.oa.mapper.GearOrderMapper;
|
||||
import com.gear.oa.mapper.GearReturnExchangeMapper;
|
||||
import com.gear.oa.service.IGearReturnExchangeService;
|
||||
|
||||
@@ -31,6 +35,8 @@ import java.util.Collection;
|
||||
public class GearReturnExchangeServiceImpl implements IGearReturnExchangeService {
|
||||
|
||||
private final GearReturnExchangeMapper baseMapper;
|
||||
private final GearOrderDetailMapper orderDetailMapper;
|
||||
private final GearOrderMapper orderMapper;
|
||||
|
||||
/**
|
||||
* 查询退换货管理
|
||||
@@ -103,6 +109,9 @@ public class GearReturnExchangeServiceImpl implements IGearReturnExchangeService
|
||||
*/
|
||||
@Override
|
||||
public Boolean insertByBo(GearReturnExchangeBo bo) {
|
||||
if (bo.getSalesmanId() == null) {
|
||||
bo.setSalesmanId(resolveSalesmanIdByOrderDetail(bo.getOrderDetailId()));
|
||||
}
|
||||
GearReturnExchange add = BeanUtil.toBean(bo, GearReturnExchange.class);
|
||||
validEntityBeforeSave(add);
|
||||
boolean flag = baseMapper.insert(add) > 0;
|
||||
@@ -117,11 +126,29 @@ public class GearReturnExchangeServiceImpl implements IGearReturnExchangeService
|
||||
*/
|
||||
@Override
|
||||
public Boolean updateByBo(GearReturnExchangeBo bo) {
|
||||
if (bo.getSalesmanId() == null) {
|
||||
bo.setSalesmanId(resolveSalesmanIdByOrderDetail(bo.getOrderDetailId()));
|
||||
}
|
||||
GearReturnExchange update = BeanUtil.toBean(bo, GearReturnExchange.class);
|
||||
validEntityBeforeSave(update);
|
||||
return baseMapper.updateById(update) > 0;
|
||||
}
|
||||
|
||||
private Long resolveSalesmanIdByOrderDetail(Long orderDetailId) {
|
||||
if (orderDetailId == null) {
|
||||
return null;
|
||||
}
|
||||
GearOrderDetail detail = orderDetailMapper.selectById(orderDetailId);
|
||||
if (detail == null || detail.getOrderId() == null) {
|
||||
return null;
|
||||
}
|
||||
GearOrder order = orderMapper.selectById(detail.getOrderId());
|
||||
if (order == null) {
|
||||
return null;
|
||||
}
|
||||
return order.getSalesmanId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存前的数据校验
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<result property="reason" column="reason"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="amount" column="amount"/>
|
||||
<result property="salesmanId" column="salesman_id"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
@@ -28,12 +29,17 @@
|
||||
gre.reason,
|
||||
gre.status,
|
||||
gre.amount,
|
||||
(CASE
|
||||
WHEN o.salesman_id IS NOT NULL THEN o.salesman_id
|
||||
ELSE gre.salesman_id
|
||||
END) AS salesmanId,
|
||||
gre.del_flag,
|
||||
gre.create_time,
|
||||
gre.create_by,
|
||||
gre.update_time,
|
||||
gre.update_by,
|
||||
god.order_id,
|
||||
gs.name AS salesmanName,
|
||||
gp.product_id AS productId,
|
||||
gp.product_code AS productCode,
|
||||
gp.product_name AS productName,
|
||||
@@ -44,6 +50,8 @@
|
||||
god.no_tax_price AS noTaxPrice
|
||||
FROM gear_return_exchange gre
|
||||
LEFT JOIN gear_order_detail god ON gre.order_detail_id = god.detail_id
|
||||
LEFT JOIN gear_order o ON god.order_id = o.order_id AND o.del_flag = 0
|
||||
LEFT JOIN gear_salesman gs ON o.salesman_id = gs.salesman_id AND gs.del_flag = 0
|
||||
LEFT JOIN gear_product gp ON god.product_id = gp.product_id
|
||||
LEFT JOIN gear_customer gc ON gre.customer_id = gc.customer_id
|
||||
${ew.customSqlSegment}
|
||||
|
||||
@@ -354,14 +354,17 @@
|
||||
<el-col :span="24">
|
||||
<el-form-item label="产品" prop="productId">
|
||||
<!-- 仅允许选择成品(product),避免半成品进入发货 -->
|
||||
<el-select v-model="orderDetailAddForm.productId" filterable clearable placeholder="请选择产品" style="width: 100%" @change="handleOrderDetailProductPicked">
|
||||
<el-option
|
||||
v-for="p in productBaseOptions"
|
||||
:key="p.productId"
|
||||
:label="`${p.productName}${p.spec ? ' ' + p.spec : ''}${p.model ? ' ' + p.model : ''}`"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
<div style="display:flex; align-items:center; gap: 10px; width: 100%;">
|
||||
<el-select v-model="orderDetailAddForm.productId" filterable clearable placeholder="请选择产品" style="flex: 1; min-width: 0;" @change="handleOrderDetailProductPicked">
|
||||
<el-option
|
||||
v-for="p in productBaseOptions"
|
||||
:key="p.productId"
|
||||
:label="`${p.productName}${p.spec ? ' ' + p.spec : ''}${p.model ? ' ' + p.model : ''}`"
|
||||
:value="p.productId"
|
||||
/>
|
||||
</el-select>
|
||||
<el-button plain type="primary" @click="openQuickAddProduct">新增成品</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -392,6 +395,42 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog title="新增成品" v-model="productQuickAddOpen" width="680px" append-to-body>
|
||||
<el-form ref="productQuickAddRef" :model="productQuickAddForm" label-width="90px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="成品名称" prop="productName">
|
||||
<el-input v-model="productQuickAddForm.productName" placeholder="请输入成品名称" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="规格" prop="spec">
|
||||
<el-input v-model="productQuickAddForm.spec" placeholder="规格" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="型号" prop="model">
|
||||
<el-input v-model="productQuickAddForm.model" placeholder="型号" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单价" prop="unitPrice">
|
||||
<el-input-number v-model="productQuickAddForm.unitPrice" :controls="false" :min="0" :precision="4" style="width: 100%;" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="productQuickAddForm.remark" type="textarea" :rows="3" placeholder="备注" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="productQuickAddOpen = false">取消</el-button>
|
||||
<el-button type="primary" :loading="productQuickAddLoading" @click="submitQuickAddProduct">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-tab-pane label="财务状态" name="finance">
|
||||
<div class="mt-4 finance-section">
|
||||
<div class="finance-title-row">
|
||||
@@ -686,7 +725,7 @@ import Receive from './receive.vue';
|
||||
import { listSalesman } from "@/api/oms/salesman";
|
||||
import { listShippingOrder, addShippingOrder, delShippingOrder } from "@/api/oms/shippingOrder";
|
||||
import { listOrderDetail, addOrderDetail, updateOrderDetail } from "@/api/oms/orderDetail";
|
||||
import { listProductBase } from "@/api/mat/product";
|
||||
import { listProductBase, addProduct } from "@/api/mat/product";
|
||||
import { sumStockQuantityByItemIds } from "@/api/wms/stock";
|
||||
import { listReceivable } from "@/api/finance/receivable";
|
||||
import { listOrderProduction, initOrderProduction, updateOrderProduction } from "@/api/oms/orderProduction";
|
||||
@@ -830,6 +869,15 @@ export default {
|
||||
model: "",
|
||||
remark: ""
|
||||
},
|
||||
productQuickAddOpen: false,
|
||||
productQuickAddLoading: false,
|
||||
productQuickAddForm: {
|
||||
productName: "",
|
||||
spec: "",
|
||||
model: "",
|
||||
unitPrice: 0,
|
||||
remark: ""
|
||||
},
|
||||
productionLoading: false,
|
||||
productionInitLoading: false,
|
||||
productionOnlyProduct: true,
|
||||
@@ -1696,6 +1744,57 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
openQuickAddProduct() {
|
||||
this.productQuickAddForm = {
|
||||
productName: "",
|
||||
spec: "",
|
||||
model: "",
|
||||
unitPrice: 0,
|
||||
remark: ""
|
||||
};
|
||||
this.productQuickAddOpen = true;
|
||||
},
|
||||
|
||||
submitQuickAddProduct() {
|
||||
const name = this.productQuickAddForm && this.productQuickAddForm.productName != null
|
||||
? String(this.productQuickAddForm.productName).trim()
|
||||
: "";
|
||||
if (!name) {
|
||||
this.$modal.msgError("请输入成品名称");
|
||||
return;
|
||||
}
|
||||
this.productQuickAddLoading = true;
|
||||
const payload = {
|
||||
productName: name,
|
||||
spec: this.productQuickAddForm.spec != null ? String(this.productQuickAddForm.spec).trim() : "",
|
||||
model: this.productQuickAddForm.model != null ? String(this.productQuickAddForm.model).trim() : "",
|
||||
unitPrice: this.productQuickAddForm.unitPrice != null ? this.productQuickAddForm.unitPrice : 0,
|
||||
remark: this.productQuickAddForm.remark != null ? String(this.productQuickAddForm.remark).trim() : "",
|
||||
productType: "product"
|
||||
};
|
||||
addProduct(payload).then(() => {
|
||||
this.$modal.msgSuccess("已新增成品");
|
||||
this.productQuickAddOpen = false;
|
||||
return listProductBase({ pageNum: 1, pageSize: 9999, productType: "product" });
|
||||
}).then(res => {
|
||||
this.productBaseOptions = (res && res.rows) ? res.rows : [];
|
||||
const list = Array.isArray(this.productBaseOptions) ? this.productBaseOptions : [];
|
||||
const hit = list.find(p => {
|
||||
if (!p) return false;
|
||||
const n = p.productName != null ? String(p.productName).trim() : "";
|
||||
const s = p.spec != null ? String(p.spec).trim() : "";
|
||||
const m = p.model != null ? String(p.model).trim() : "";
|
||||
return n === payload.productName && s === payload.spec && m === payload.model;
|
||||
});
|
||||
if (hit && hit.productId != null) {
|
||||
this.orderDetailAddForm.productId = hit.productId;
|
||||
this.handleOrderDetailProductPicked(hit.productId);
|
||||
}
|
||||
}).finally(() => {
|
||||
this.productQuickAddLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
/** 订单明细:选中产品后自动带出单位/单价(不涉及库存) */
|
||||
handleOrderDetailProductPicked(productId) {
|
||||
const list = Array.isArray(this.productBaseOptions) ? this.productBaseOptions : [];
|
||||
|
||||
@@ -68,12 +68,32 @@
|
||||
<el-dialog :title="title" v-model="open" width="500px" append-to-body>
|
||||
<el-form ref="returnExchangeRef" :model="form" :rules="rules" label-width="80px">
|
||||
<el-form-item label="订单明细" prop="orderDetailId">
|
||||
<el-select v-model="form.orderDetailId" placeholder="请选择订单明细">
|
||||
<el-option v-for="item in orderDetailList" :key="item.detailId" :value="item.detailId">
|
||||
<ProductInfo :productId="item.productId" />
|
||||
<el-select v-model="form.orderDetailId" placeholder="请选择订单明细" filterable>
|
||||
<el-option
|
||||
v-for="item in orderDetailList"
|
||||
:key="item.detailId"
|
||||
:value="item.detailId"
|
||||
:label="orderDetailLabel(item)"
|
||||
>
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; gap: 12px; width: 100%;">
|
||||
<div style="flex: 1; min-width: 0;">
|
||||
<div style="font-weight: 600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
|
||||
{{ item.productName || '-' }}
|
||||
</div>
|
||||
<div style="color:#909399; font-size: 12px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;">
|
||||
{{ item.productCode || '-' }}
|
||||
</div>
|
||||
</div>
|
||||
<div style="color:#606266; font-size: 12px; flex: none; white-space:nowrap;">
|
||||
{{ (item.spec || '-') + (item.model ? (' / ' + item.model) : '') }}
|
||||
</div>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="销售员">
|
||||
<el-input :model-value="orderSalesmanName" disabled placeholder="-" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户ID" prop="customerId">
|
||||
<CustomerSelect v-model="form.customerId" />
|
||||
</el-form-item>
|
||||
@@ -100,8 +120,8 @@
|
||||
<script setup name="ReturnExchange">
|
||||
import { listReturnExchange, getReturnExchange, delReturnExchange, addReturnExchange, updateReturnExchange } from "@/api/oa/returnExchange";
|
||||
import { listOrderDetail } from "@/api/oms/orderDetail";
|
||||
import { getOrder } from "@/api/oms/order";
|
||||
import CustomerSelect from '@/components/CustomerSelect/index.vue';
|
||||
import ProductInfo from '@/components/Renderer/ProductInfo.vue';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
|
||||
@@ -123,6 +143,23 @@ const multiple = ref(true);
|
||||
const total = ref(0);
|
||||
const title = ref("");
|
||||
|
||||
const orderInfo = ref(null);
|
||||
const orderSalesmanName = computed(() => {
|
||||
const o = orderInfo.value;
|
||||
if (!o) return "";
|
||||
return o.salesManager || "-";
|
||||
});
|
||||
|
||||
function orderDetailLabel(item) {
|
||||
if (!item) return '-';
|
||||
const name = item.productName || '-';
|
||||
const code = item.productCode ? `(${item.productCode})` : '';
|
||||
const spec = item.spec || '';
|
||||
const model = item.model || '';
|
||||
const sm = [spec, model].filter(Boolean).join('/');
|
||||
return `${name}${code}${sm ? ' ' + sm : ''}`;
|
||||
}
|
||||
|
||||
const formatterTime = (time) => {
|
||||
return proxy.parseTime(time, '{y}-{m}-{d}')
|
||||
}
|
||||
@@ -148,9 +185,22 @@ const { queryParams, form, rules } = toRefs(data);
|
||||
|
||||
watch(() => props.orderId, () => {
|
||||
getOrderDetailList();
|
||||
fetchOrderInfo();
|
||||
getList();
|
||||
}, { immediate: true });
|
||||
|
||||
function fetchOrderInfo() {
|
||||
if (!props.orderId) {
|
||||
orderInfo.value = null;
|
||||
return;
|
||||
}
|
||||
getOrder(props.orderId).then(res => {
|
||||
orderInfo.value = res && res.data ? res.data : null;
|
||||
}).catch(() => {
|
||||
orderInfo.value = null;
|
||||
});
|
||||
}
|
||||
|
||||
/** 查询退换货管理列表 */
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
@@ -186,6 +236,7 @@ function reset() {
|
||||
reason: null,
|
||||
status: null,
|
||||
amount: null,
|
||||
salesmanId: null,
|
||||
delFlag: null,
|
||||
createTime: null,
|
||||
createBy: null,
|
||||
@@ -217,6 +268,14 @@ function handleSelectionChange(selection) {
|
||||
/** 新增按钮操作 */
|
||||
function handleAdd() {
|
||||
reset();
|
||||
if (orderInfo.value) {
|
||||
if (orderInfo.value.customerId != null) {
|
||||
form.value.customerId = orderInfo.value.customerId;
|
||||
}
|
||||
if (orderInfo.value.salesmanId != null) {
|
||||
form.value.salesmanId = orderInfo.value.salesmanId;
|
||||
}
|
||||
}
|
||||
open.value = true;
|
||||
title.value = "添加退换货管理";
|
||||
}
|
||||
@@ -229,6 +288,9 @@ function handleUpdate(row) {
|
||||
getReturnExchange(_returnExchangeId).then(response => {
|
||||
loading.value = false;
|
||||
form.value = response.data;
|
||||
if (form.value && form.value.salesmanId == null && orderInfo.value && orderInfo.value.salesmanId != null) {
|
||||
form.value.salesmanId = orderInfo.value.salesmanId;
|
||||
}
|
||||
open.value = true;
|
||||
title.value = "修改退换货管理";
|
||||
});
|
||||
|
||||
@@ -110,7 +110,13 @@
|
||||
<el-table v-loading="orderLoading" :data="orderList">
|
||||
<el-table-column label="订单编号" prop="orderCode" min-width="160" />
|
||||
<el-table-column label="客户" prop="customerName" min-width="200" />
|
||||
<el-table-column label="状态" prop="orderStatus" width="120" />
|
||||
<el-table-column label="状态" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="orderStatusTagType(scope.row.orderStatus)" size="small">
|
||||
{{ orderStatusLabel(scope.row.orderStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" prop="createTime" width="180" />
|
||||
</el-table>
|
||||
|
||||
@@ -240,7 +246,13 @@
|
||||
<el-table-column label="发货时间" prop="shipTime" width="180" />
|
||||
<el-table-column label="物流公司" prop="logisticsCompany" min-width="140" />
|
||||
<el-table-column label="运单号" prop="logisticsNo" min-width="180" />
|
||||
<el-table-column label="状态" prop="status" width="120" />
|
||||
<el-table-column label="状态" width="120" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag :type="shippingStatusTagType(scope.row.status)" size="small">
|
||||
{{ shippingStatusLabel(scope.row.status) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
@@ -633,6 +645,28 @@ export default {
|
||||
return "info";
|
||||
},
|
||||
|
||||
shippingStatusLabel(status) {
|
||||
const n = Number(status);
|
||||
if (Number.isFinite(n)) {
|
||||
if (n === 0) return "未发货";
|
||||
if (n === 1) return "已打印";
|
||||
if (n === 2) return "已发货";
|
||||
if (n === 3) return "已完成";
|
||||
}
|
||||
const t = String(status ?? "");
|
||||
return t || "-";
|
||||
},
|
||||
|
||||
shippingStatusTagType(status) {
|
||||
const n = Number(status);
|
||||
if (Number.isFinite(n)) {
|
||||
if (n === 3) return "success";
|
||||
if (n === 2) return "primary";
|
||||
if (n === 1) return "warning";
|
||||
}
|
||||
return "info";
|
||||
},
|
||||
|
||||
loadShippingOrders() {
|
||||
if (!this.selectedSalesmanId) return;
|
||||
this.shippingLoading = true;
|
||||
|
||||
Reference in New Issue
Block a user