21 小时以前 e731bf5f64d71ed93a570d505c52dc44d491175e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.sales.mapper.SalesLedgerProductMapper">
 
    <select id="selectSalesLedgerProductList" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
        SELECT
        T1.id,
        T1.sales_ledger_id,
        T1.warn_num,
        T1.quantity,
        T1.min_stock,
        T1.tax_rate,
        T1.tax_inclusive_unit_price,
        T1.tax_inclusive_total_price,
        T1.tax_exclusive_total_price,
        T1.invoice_type,
        T1.type,
        T1.product_id,
        T1.product_model_id,
        T1.register,
        T1.register_date,
        T1.approve_status,
        T1.is_checked,
        T1.is_production,
        T1.create_user,
        T1.dept_id,
        p.product_name as product_category,
        pm.model as specification_model,
        pm.unit as unit,
        CASE
        WHEN (IFNULL(t2.qualitity, 0) - IFNULL(t2.locked_quantity, 0)) >0 THEN 1
        ELSE 0
        END as has_sufficient_stock,
        (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0) - IFNULL(t5.pending_approval_quantity, 0)) as no_quantity,
        IFNULL(t3.shipped_quantity, 0) as shipped_quantity,
        IFNULL(t6.return_quantity, 0) as return_quantity,
        IFNULL(t4.approved_stock_in_num, 0) as approved_stock_in_num,
        IFNULL(t5.pending_approval_quantity, 0) as pending_approval_quantity,
        CASE
         WHEN IFNULL(t3.shipped_quantity, 0) = 0 AND IFNULL(t5.pending_approval_quantity, 0) = 0 THEN '待发货'
         WHEN IFNULL(t3.shipped_quantity, 0) = 0 AND IFNULL(t5.pending_approval_quantity, 0) > 0 THEN '审批中'
         WHEN (IFNULL(T1.quantity, 0) - IFNULL(t3.shipped_quantity, 0)) > 0 THEN '部分发货'
        ELSE '已发货'
        END as shippingStatus,
        CASE
         WHEN T1.type != 2 THEN NULL
         WHEN IFNULL(t4.approved_stock_in_num, 0) &lt;= 0 THEN '待入库'
         WHEN IFNULL(t4.approved_stock_in_num, 0) &gt;= IFNULL(T1.quantity, 0) THEN '完全入库'
        ELSE '入库中'
        END AS stock_in_approval_status
        FROM
        sales_ledger_product T1
        LEFT JOIN (
        SELECT product_model_id, SUM(qualitity) as qualitity, SUM(locked_quantity) as locked_quantity
        FROM stock_inventory
        GROUP BY product_model_id
        ) t2 ON T1.product_model_id = t2.product_model_id
        LEFT JOIN (
        SELECT
            slp.id AS sales_ledger_product_id,
            IFNULL(SUM(so.total_sale_out_num), 0) AS shipped_quantity
        FROM sales_ledger_product slp
        LEFT JOIN (
            -- 采购台账的「已销售数量」:油品出库不再产 shipping_product_detail,
            -- 改由绑定行的分摊数量反推 —— 出库单的 规格+批次 对上采购入库批次,即为该采购台账卖掉的量
            SELECT
                pl.id AS purchase_ledger_id,
                sir.product_model_id,
                SUM(b.quantity) AS total_sale_out_num
            FROM stock_out_record_sales_ledger b
            INNER JOIN stock_out_record sor
                ON sor.id = b.stock_out_record_id
               AND sor.approval_status = 1
               AND (sor.type IS NULL OR sor.type = '')
            INNER JOIN stock_in_record sir
                ON sir.product_model_id = sor.product_model_id
               AND (
                    (sir.batch_no IS NOT NULL AND sir.batch_no = sor.batch_no)
                    OR (sir.batch_no IS NULL AND sor.batch_no IS NULL)
               )
               AND sir.approval_status = 1
               AND sir.record_type IN ('7', '10')
            LEFT JOIN quality_inspect qi
                ON sir.record_type = '10'
               AND sir.record_id = qi.id
            LEFT JOIN purchase_ledger pl
                ON pl.id = IF(sir.record_type = '7', sir.record_id, qi.purchase_ledger_id)
            WHERE pl.id IS NOT NULL
            GROUP BY pl.id, sir.product_model_id
        ) so ON so.purchase_ledger_id = slp.sales_ledger_id
            AND so.product_model_id = slp.product_model_id
        WHERE slp.type = 2
        GROUP BY slp.id
 
        UNION ALL
 
        -- 销售台账(type=1): 已发货量直接按到货记录汇总。到货记录本身就是「实际到了多少」的事实,
        -- 不再绕 shipping_info + shipping_product_detail
        SELECT
            sla.sales_ledger_product_id AS sales_ledger_product_id,
            IFNULL(SUM(sla.arrival_quantity), 0) AS shipped_quantity
        FROM sales_ledger_arrival sla
        WHERE sla.sales_ledger_product_id IS NOT NULL
        GROUP BY sla.sales_ledger_product_id
        ) t3 ON t3.sales_ledger_product_id = T1.id
        LEFT JOIN (
        SELECT rel.sales_ledger_product_id,
               IFNULL(SUM(rel.stock_in_num), 0) AS approved_stock_in_num
        FROM (
            SELECT slp.id AS sales_ledger_product_id,
                   sir.stock_in_num
            FROM stock_in_record sir
            INNER JOIN sales_ledger_product slp
                ON slp.type = 2
                AND TRIM(sir.record_type) = '7'
                AND sir.record_id = slp.sales_ledger_id
                AND (
                    (sir.batch_no IS NOT NULL AND sir.batch_no LIKE CONCAT('%-', slp.id))
                    OR (sir.batch_no IS NULL AND sir.product_model_id = slp.product_model_id)
                )
            WHERE sir.approval_status = 1
 
            UNION ALL
 
            SELECT slp.id AS sales_ledger_product_id,
                   sir.stock_in_num
            FROM stock_in_record sir
            INNER JOIN quality_inspect qi
                ON TRIM(sir.record_type) = '10'
                AND sir.record_id = qi.id
            INNER JOIN sales_ledger_product slp
                ON slp.type = 2
                AND slp.sales_ledger_id = qi.purchase_ledger_id
                AND slp.product_model_id = qi.product_model_id
            WHERE sir.approval_status = 1
        ) rel
        GROUP BY rel.sales_ledger_product_id
        ) t4 ON t4.sales_ledger_product_id = T1.id
        LEFT JOIN (
        SELECT si.sales_ledger_product_id, IFNULL(SUM(spd.quantity), 0) as pending_approval_quantity
        FROM shipping_info si
        LEFT JOIN shipping_product_detail spd ON si.id = spd.shipping_info_id
        WHERE si.status IN ('待审核', '审核中')
           OR (si.status = '审核通过' AND NOT EXISTS (
                SELECT 1 FROM stock_out_record sor
                WHERE sor.record_id = si.id
                  AND TRIM(sor.record_type) = '13'
                  AND sor.approval_status = 1
           ))
        GROUP BY si.sales_ledger_product_id
 
        UNION ALL
 
        -- 油品出库待审批 / 待确认:还没到货,算「审批中」,与 t3 的到货量互补。
        -- 只有绑定了卖油台账的出库才占这条分支(代储、客存不产绑定行)
        SELECT b.sales_ledger_product_id AS sales_ledger_product_id,
               IFNULL(SUM(b.quantity), 0) AS pending_approval_quantity
        FROM stock_out_record_sales_ledger b
        INNER JOIN stock_out_record sor
            ON sor.id = b.stock_out_record_id
           AND sor.approval_status IN (0, 3)
           AND (sor.type IS NULL OR sor.type = '')
        WHERE b.sales_ledger_product_id IS NOT NULL
        GROUP BY b.sales_ledger_product_id
        ) t5 ON t5.sales_ledger_product_id = T1.id
        LEFT JOIN (
            SELECT
                prop.sales_ledger_product_id,
                IFNULL(SUM(prop.return_quantity), 0) AS return_quantity
            FROM purchase_return_order_products prop
            LEFT JOIN purchase_return_orders pro
                ON pro.id = prop.purchase_return_order_id
            GROUP BY prop.sales_ledger_product_id
 
            UNION ALL
 
            SELECT
                si.sales_ledger_product_id,
                IFNULL(SUM(rsp.num), 0) AS return_quantity
            FROM return_sale_product rsp
            INNER JOIN return_management rm ON rm.id = rsp.return_management_id
            INNER JOIN shipping_info si ON si.id = rm.shipping_id
            INNER JOIN stock_in_record sir ON sir.record_id = rsp.id
                AND TRIM(sir.record_type) IN ('14','15')
                AND sir.approval_status = 1
            WHERE si.sales_ledger_product_id IS NOT NULL
            GROUP BY si.sales_ledger_product_id
        ) t6 ON t6.sales_ledger_product_id = T1.id
        left join product_model pm ON T1.product_model_id = pm.id
        left join product p ON pm.product_id = p.id
        <where>
            <if test="salesLedgerProduct.salesLedgerId != null">
                AND T1.sales_ledger_id = #{salesLedgerProduct.salesLedgerId}
            </if>
            <if test="salesLedgerProduct.type != null">
                AND T1.type = #{salesLedgerProduct.type}
            </if>
        </where>
        ORDER BY T1.register_date DESC
    </select>
 
    <select id="selectSalesLedgerProductByMainId" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
        select slp.*
        from quality_inspect qi
                 left join production_product_main ppm on qi.product_main_id = ppm.id
                 left join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 left join production_order po on pot.production_order_id = po.id
                 left join production_plan pp_main
                           on find_in_set(pp_main.id, replace(replace(replace(po.production_plan_ids, '[', ''), ']', ''), ' ', '')) > 0
                 left join sales_ledger_product slp on slp.sales_ledger_id = pp_main.sales_ledger_id
            and slp.product_model_id = po.product_model_id
            and slp.type = 1
        where qi.product_main_id = #{productMainId}
          and slp.id is not null
        order by slp.id desc
        limit 1
    </select>
    <select id="procurementBusinessSummaryListPage"
            resultType="com.ruoyi.purchase.dto.ProcurementBusinessSummaryDto">
        SELECT
        slp.product_category AS productCategory,
        slp.specification_model AS specificationModel,
        sl.supplier_name AS supplierName,
        SUM(slp.quantity) AS purchaseNum,
        SUM(slp.tax_inclusive_total_price) AS purchaseAmount,
        COUNT(DISTINCT slp.sales_ledger_id) AS purchaseTimes,
        <!-- 平均单价 = 总采购金额/总采购数量,保留2位小数,避免除0 -->
        ROUND(IF(SUM(slp.quantity) = 0, 0, SUM(slp.tax_inclusive_total_price) / SUM(slp.quantity)), 2) AS averagePrice,
        <!-- 该产品大类下最后一个录入日期(取台账主表的entry_date) -->
        MAX(sl.entry_date) AS entryDate,
        COALESCE(NULLIF(SUM(t1.return_quantity), 0), 0) AS return_quantity,
        COALESCE(SUM(t2.total_amount), 0) AS return_amount
        FROM sales_ledger_product slp
        <!-- 关联台账主表:获取录入日期entry_date -->
        LEFT JOIN purchase_ledger sl ON slp.sales_ledger_id = sl.id
        left join purchase_return_order_products as t1 on t1.sales_ledger_product_id = slp.id
        left join purchase_return_orders as t2 on t2.id = t1.purchase_return_order_id
        WHERE slp.type = 2 <!-- 固定筛选:采购台账(type=2) -->
        <!-- 采购日期筛选:可选条件 -->
        <if test="req.entryDateStart != null and req.entryDateEnd != null">
            AND sl.entry_date BETWEEN #{req.entryDateStart} AND #{req.entryDateEnd} <!-- 时间范围:非空有效 -->
        </if>
        <!-- 产品大类筛选:可选条件 -->
        <if test="req.productCategory != null and req.productCategory != ''">
            AND slp.product_category = #{req.productCategory}
        </if>
        GROUP BY slp.product_category, slp.specification_model, sl.supplier_name
        ORDER BY slp.product_category
    </select>
    <select id="selectProductBomStructure" resultType="com.ruoyi.sales.dto.LossProductModelDto">
        select
            a.model,
            a.product_name,
            a.unit,
            sum(a.single_quantity) AS loss_num
        from (SELECT ps.unit,
                     ps.unit_quantity,
                     pm1.model,
                     p.product_name,
                     ps.unit_quantity * slp.quantity AS single_quantity
              FROM sales_ledger sl
                       LEFT JOIN sales_ledger_product slp ON slp.sales_ledger_id = sl.id and slp.type = 1
                       LEFT JOIN product_model pm ON pm.id = slp.product_model_id
                       LEFT JOIN product_bom pb ON pb.product_model_id = pm.id
                       LEFT JOIN product_structure ps ON pb.id = ps.bom_id
                       LEFT JOIN product_model pm1 ON pm1.id = ps.product_model_id
                       LEFT JOIN product p ON p.id = pm1.product_id
               WHERE sl.id = #{salesLedegerId}) A
        group by a.model, a.product_name, a.unit
    </select>
    <select id="selectProduct" resultType="com.ruoyi.sales.pojo.SalesLedgerProduct">
        select
            p.product_name as product_category,
            pm.model as specification_model,
            pm.id as product_model_id
        from product_model pm
        left join product p on pm.product_id = p.id
    </select>
 
    <select id="selectProductSalesAnalysis" resultType="java.util.Map">
        SELECT
            product_category as name,
            SUM( tax_inclusive_total_price ) AS value
        FROM
            sales_ledger_product
        WHERE
            type = 1
        GROUP BY
            product_category
        ORDER BY
            value DESC
        LIMIT 5
    </select>
 
    <!-- 采购品分布:与「各产品销售金额分析」同口径,直接按采购明细上的品类聚合。
         不能再按产品树「原材料」子树过滤 —— 采购台账实际登记的品类(柴油、灭火器)分别挂在
         「成品/成品油」「设备设施/公共安全设备」下,按子树过滤会恒为空 -->
    <select id="selectRawMaterialPurchaseAnalysis" resultType="java.util.Map">
        SELECT
            slp.product_category AS name,
            SUM( slp.tax_inclusive_total_price ) AS value
        FROM
            sales_ledger_product slp
        WHERE
            slp.type = 2
            AND slp.product_category IS NOT NULL
            AND slp.product_category != ''
        GROUP BY
            slp.product_category
        ORDER BY
            value DESC
        LIMIT 5
    </select>
 
    <select id="selectProductCountByTypeAndDate" resultType="int">
        SELECT IFNULL(COUNT(*), 0)
        FROM sales_ledger_product
        WHERE type = #{type}
        <if test="startDate != null">
            AND register_date &gt;= #{startDate}
        </if>
        <if test="endDate != null">
            AND register_date &lt;= #{endDate}
        </if>
    </select>
 
    <select id="selectRawMaterialExpense" resultType="java.math.BigDecimal">
        WITH RECURSIVE product_tree AS (SELECT id
                                        FROM product
                                        WHERE product_name = '原材料'
 
                                        UNION ALL
 
                                        SELECT p.id
                                        FROM product p
                                                 INNER JOIN product_tree pt ON p.parent_id = pt.id)
        SELECT IFNULL(SUM(slp.tax_inclusive_total_price), 0)
        FROM sales_ledger_product slp
        WHERE slp.type = 2
          AND slp.product_id IN (SELECT id
                                 FROM product_tree);
 
    </select>
</mapper>