#1004·mall

Administrative fee adjustments leave order pay_amount unchanged, and Alipay uses the outdated payable

Author: YutuSecCreated Sep 16, 2026Updated Sep 16, 2026
## Affected product and snapshot - Product: `macrozheng/mall` - Modules: `mall-admin`, `mall-portal` - Source-reviewed commit: `dcaa93b3150352e5044708d7211b5bed0af4509f` - Fee adjustment endpoint: `POST /order/update/moneyInfo` - Downstream payment endpoints: `GET /alipay/pay` and `GET /alipay/webPay` - Dynamic verification: local Docker deployment on 2026-09-15, with `mall-admin` on port 8080 and `mall-portal` on port 8085 ## Summary The administrative fee-adjustment endpoint updates `oms_order.freight_amount` and `oms_order.discount_amount` without recalculating `oms_order.pay_amount`. This behavior was reproduced locally: an administrator changed an unpaid order's `discount_amount` from CNY 0.00 to CNY -500.00. The API returned success and persisted the adjustment, while `pay_amount` remained unchanged at CNY -824.00. A subsequent member order-detail request returned the same values. Source review confirms that freight adjustments follow the same partial-update path. Although the order's payable calculation explicitly includes freight, changing freight through this endpoint does not update the stored payable. The reviewed Alipay implementation reads this stored `pay_amount` and uses it as the payment request's `total_amount`. Consequently, a freight increase can be omitted from a subsequently initiated payment. ## Root cause ### 1. Fee adjustments do not update the payable [[OmsOrderServiceImpl.updateMoneyInfo()](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-admin/src/main/java/com/macro/mall/service/impl/OmsOrderServiceImpl.java#L119-L134)](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-admin/src/main/java/com/macro/mall/service/impl/OmsOrderServiceImpl.java#L119-L134) creates a partial order update: ```java OmsOrder order = new OmsOrder(); order.setId(moneyInfoParam.getOrderId()); order.setFreightAmount(moneyInfoParam.getFreightAmount()); order.setDiscountAmount(moneyInfoParam.getDiscountAmount()); order.setModifyTime(new Date()); int count = orderMapper.updateByPrimaryKeySelective(order); ``` The method does not load the existing monetary components, calculate the adjusted payable, or call `setPayAmount()`. The [[selective mapper update](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-mbg/src/main/resources/com/macro/mall/mapper/OmsOrderMapper.xml#L646-L684)](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-mbg/src/main/resources/com/macro/mall/mapper/OmsOrderMapper.xml#L646-L684) updates `pay_amount` only when the supplied `payAmount` is non-null. Therefore, the previous payable is preserved while the submitted fee fields are updated. ### 2. Freight is part of the payable calculation [[OmsPortalOrderServiceImpl.calcPayAmount()](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java#L548-L555)](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/OmsPortalOrderServiceImpl.java#L548-L555) calculates: ```text pay_amount = total_amount + freight_amount - promotion_amount - coupon_amount - integration_amount ``` Updating freight without recalculating `pay_amount` breaks this relationship. ### 3. Payment initiation consumes the stored payable [[AlipayServiceImpl.pay()](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java#L55-L65)](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java#L55-L65) and [[webPay()](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java#L153-L163)](https://github.com/macrozheng/mall/blob/dcaa93b3150352e5044708d7211b5bed0af4509f/mall-portal/src/main/java/com/macro/mall/portal/service/impl/AlipayServiceImpl.java#L153-L163) load the order and use: ```java BigDecimal totalAmount = order.getPayAmount(); bizContent.put("total_amount", totalAmount); ``` Neither method recalculates the payable from the updated monetary components.

1. Read the unpaid order before adjustment

The recorded test used order ID 95, with status=0.

SELECT id, status, total_amount, pay_amount,
      coupon_amount, promotion_amount,
      freight_amount, discount_amount
FROM oms_order
WHERE id = 95;
Field | Before adjustment -- | -- id | 95 status | 0 total_amount | 176.00 coupon_amount | 1000.00 promotion_amount | 0.00 freight_amount | 0.00 discount_amount | 0.00 pay_amount | -824.00

A subsequent payment request:

GET /alipay/pay?outTradeNo=<ORDER_SN>&subject=freight-adjustment HTTP/1.1
Host: localhost:8085

uses the stored CNY 100.00 as total_amount, omitting the CNY 20.00 freight increase. /alipay/webPay uses the same amount source.

The administrator performs an authorized fee adjustment, and the buyer subsequently initiates payment for their order. This scenario requires neither a client-supplied payment amount nor an excessive coupon deduction.

The fee-adjustment API and database behavior were dynamically verified as shown above. The positive-freight example and its Alipay consequence are supported by source review; a completed Alipay sandbox transaction is not part of the recorded test.

Expected behavior

An accepted monetary adjustment should update the payable consistently within the same transaction.