调整命名

This commit is contained in:
caojia
2026-11-11 00:18:12 +08:00
parent fca999c384
commit 41cefd5fd5
93 changed files with 276 additions and 280 deletions
@@ -0,0 +1,100 @@
<?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.bms.ar.mapper.ArBalanceWriteoffMapper">
<resultMap id="ArBalanceWriteoffResult" type="ArBalanceWriteoff">
<id property="writeoffId" column="writeoff_id"/>
<result property="writeoffNo" column="writeoff_no"/>
<result property="arBillId" column="ar_bill_id"/>
<result property="billNo" column="bill_no"/>
<result property="customerId" column="customer_id"/>
<result property="receiptId" column="receipt_id"/>
<result property="accountId" column="account_id"/>
<result property="currency" column="currency"/>
<result property="writeoffAmount" column="writeoff_amount"/>
<result property="balanceFlowId" column="balance_flow_id"/>
<result property="reverseFlowId" column="reverse_flow_id"/>
<result property="writeoffDate" column="writeoff_date"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="createUserId" column="create_user_id"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="cancelUserId" column="cancel_user_id"/>
<result property="cancelBy" column="cancel_by"/>
<result property="cancelTime" column="cancel_time"/>
<result property="cancelRemark" column="cancel_remark"/>
<result property="billName" column="bill_name"/>
<result property="customerName" column="customer_name"/>
</resultMap>
<sql id="selectColumns">
select w.writeoff_id, w.writeoff_no, w.ar_bill_id, w.bill_no, w.customer_id, w.receipt_id, w.account_id,
w.currency, w.writeoff_amount, w.balance_flow_id, w.reverse_flow_id,
w.writeoff_date, w.status, w.remark, w.create_user_id, w.create_by, w.create_time,
w.cancel_user_id, w.cancel_by, w.cancel_time, w.cancel_remark,
b.bill_name, b.customer_name
from ar_balance_writeoff w
left join ar_bill b on b.ar_bill_id = w.ar_bill_id
</sql>
<insert id="insertArBalanceWriteoff" parameterType="ArBalanceWriteoff"
useGeneratedKeys="true" keyProperty="writeoffId">
insert into ar_balance_writeoff (
writeoff_no, ar_bill_id, bill_no, customer_id, receipt_id, account_id, currency,
writeoff_amount, balance_flow_id, reverse_flow_id, writeoff_date,
status, remark, create_user_id, create_by, create_time
) values (
#{writeoffNo}, #{arBillId}, #{billNo}, #{customerId}, #{receiptId}, #{accountId}, #{currency},
#{writeoffAmount}, #{balanceFlowId}, #{reverseFlowId}, #{writeoffDate},
#{status}, #{remark}, #{createUserId}, #{createBy}, sysdate()
)
</insert>
<update id="updateFlowRefs">
update ar_balance_writeoff
set account_id = #{accountId},
balance_flow_id = #{balanceFlowId}
where writeoff_id = #{writeoffId}
</update>
<select id="selectByIdForUpdate" resultMap="ArBalanceWriteoffResult">
<include refid="selectColumns"/>
where w.writeoff_id = #{writeoffId}
for update
</select>
<update id="updateCancelled">
update ar_balance_writeoff
set status = #{status},
reverse_flow_id = #{reverseFlowId},
cancel_user_id = #{cancelUserId},
cancel_by = #{cancelBy},
cancel_time = sysdate(),
cancel_remark = #{cancelRemark}
where writeoff_id = #{writeoffId} and status = #{effectiveStatus}
</update>
<select id="selectWriteoffList" resultMap="ArBalanceWriteoffResult">
<include refid="selectColumns"/>
<where>
<if test="query.customerId != null">and w.customer_id = #{query.customerId}</if>
<if test="query.arBillId != null">and w.ar_bill_id = #{query.arBillId}</if>
<if test="query.status != null and query.status != ''">and w.status = #{query.status}</if>
<if test="query.currency != null and query.currency != ''">and w.currency = #{query.currency}</if>
<if test="query.writeoffNo != null and query.writeoffNo != ''">and w.writeoff_no like concat('%', #{query.writeoffNo}, '%')</if>
<if test="query.billNo != null and query.billNo != ''">and w.bill_no like concat('%', #{query.billNo}, '%')</if>
<if test="query.receiptId != null">and w.receipt_id = #{query.receiptId}</if>
<if test="query.params != null and query.params.beginTime != null and query.params.beginTime != ''">
and date_format(w.writeoff_date,'%y%m%d') &gt;= date_format(#{query.params.beginTime},'%y%m%d')
</if>
<if test="query.params != null and query.params.endTime != null and query.params.endTime != ''">
and date_format(w.writeoff_date,'%y%m%d') &lt;= date_format(#{query.params.endTime},'%y%m%d')
</if>
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>
</where>
order by w.create_time desc, w.writeoff_id desc
</select>
</mapper>
@@ -0,0 +1,69 @@
<?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.bms.ar.mapper.ArBankAccountMapper">
<resultMap id="ArBankAccountResult" type="ArBankAccount">
<id property="bankAccountId" column="bank_account_id"/>
<result property="accountName" column="account_name"/>
<result property="accountNo" column="account_no"/>
<result property="bankName" column="bank_name"/>
<result property="currency" column="currency"/>
<result property="isDefault" column="is_default"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<select id="selectDefaultByCurrency" resultMap="ArBankAccountResult">
select bank_account_id,
account_name,
account_no,
bank_name,
currency,
is_default,
status,
remark,
create_by,
create_time,
update_by,
update_time
from ar_bank_account
where currency = #{currency}
and status = '0'
order by is_default desc, bank_account_id limit 1
</select>
<sql id="enabledColumns">
select bank_account_id,
account_name,
account_no,
bank_name,
currency,
is_default,
status,
remark,
create_by,
create_time,
update_by,
update_time
from ar_bank_account
where status = '0'
</sql>
<select id="selectEnabledById" resultMap="ArBankAccountResult">
<include refid="enabledColumns"/>
and bank_account_id = #{bankAccountId}
</select>
<select id="selectEnabledList" resultMap="ArBankAccountResult">
<include refid="enabledColumns"/>
<if test="currency != null and currency != ''">
and currency = #{currency}
</if>
order by is_default desc, currency asc, bank_account_id asc
</select>
</mapper>
@@ -0,0 +1,176 @@
<?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.bms.ar.mapper.ArBillDetailFeeMapper">
<!-- 账单明细费用项读写;批量查询仅接收当前明细批次的 ID。 -->
<resultMap id="ArBillDetailFeeResult" type="ArBillDetailFee">
<id property="detailFeeId" column="detail_fee_id"/>
<result property="detailId" column="detail_id"/>
<result property="prcIncomeBillFeeId" column="prc_income_bill_fee_id"/>
<result property="feeNo" column="fee_no"/>
<result property="feeType" column="fee_type"/>
<result property="feeName" column="fee_name"/>
<result property="scId" column="sc_id"/>
<result property="quantity" column="quantity"/>
<result property="unit" column="unit"/>
<result property="unitPrice" column="unit_price"/>
<result property="amount" column="amount"/>
<result property="productAmount" column="product_amount"/>
<result property="redlineAmount" column="redline_amount"/>
<result property="currency" column="currency"/>
<result property="calculationFormula" column="calculation_formula"/>
<result property="roundMode" column="round_mode"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectByDetailId" parameterType="long" resultMap="ArBillDetailFeeResult">
select detail_fee_id,
detail_id,
prc_income_bill_fee_id,
fee_no,
fee_type,
fee_name,
sc_id,
quantity,
unit,
unit_price,
amount,
product_amount,
redline_amount,
currency,
calculation_formula,
round_mode,
remark,
create_by,
create_time
from ar_bill_detail_fee
where detail_id = #{detailId}
order by fee_no, detail_fee_id
</select>
<select id="selectByBillIdAndDetailId" resultMap="ArBillDetailFeeResult">
select f.detail_fee_id,
f.detail_id,
f.prc_income_bill_fee_id,
f.fee_no,
f.fee_type,
f.fee_name,
f.sc_id,
f.quantity,
f.unit,
f.unit_price,
f.amount,
f.product_amount,
f.redline_amount,
f.currency,
f.calculation_formula,
f.round_mode,
f.remark,
f.create_by,
f.create_time
from ar_bill_detail_fee f
inner join ar_bill_detail d on d.detail_id = f.detail_id
where d.ar_bill_id = #{arBillId}
and f.detail_id = #{detailId}
order by f.fee_no, f.detail_fee_id
</select>
<select id="selectByBillIdAndDetailIdScoped" resultMap="ArBillDetailFeeResult">
select f.detail_fee_id,
f.detail_id,
f.prc_income_bill_fee_id,
f.fee_no,
f.fee_type,
f.fee_name,
f.sc_id,
f.quantity,
f.unit,
f.unit_price,
f.amount,
f.product_amount,
f.redline_amount,
f.currency,
f.calculation_formula,
f.round_mode,
f.remark,
f.create_by,
f.create_time
from ar_bill_detail_fee f
inner join ar_bill_detail d on d.detail_id = f.detail_id
where d.ar_bill_id = #{arBillId}
and f.detail_id = #{detailId}
AND EXISTS (SELECT 1 FROM ar_bill b WHERE b.ar_bill_id = d.ar_bill_id <include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>)
order by f.fee_no, f.detail_fee_id
</select>
<select id="selectByBillId" parameterType="long" resultMap="ArBillDetailFeeResult">
select detail_fee_id,
detail_id,
prc_income_bill_fee_id,
fee_no,
fee_type,
fee_name,
sc_id,
quantity,
unit,
unit_price,
amount,
product_amount,
redline_amount,
currency,
calculation_formula,
round_mode,
remark,
create_by,
create_time
from ar_bill_detail_fee
where detail_id in (select detail_id from ar_bill_detail where ar_bill_id = #{arBillId})
order by detail_id, fee_no, detail_fee_id
</select>
<select id="selectByDetailIds" resultMap="ArBillDetailFeeResult">
select detail_fee_id, detail_id, prc_income_bill_fee_id, fee_no, fee_type, fee_name, sc_id, quantity,
unit, unit_price, amount, product_amount, redline_amount, currency, calculation_formula, round_mode, remark, create_by, create_time
from ar_bill_detail_fee
where detail_id in
<foreach collection="detailIds" item="detailId" open="(" separator="," close=")">
#{detailId}
</foreach>
order by detail_id, fee_no, detail_fee_id
</select>
<insert id="insert" parameterType="ArBillDetailFee" useGeneratedKeys="true" keyProperty="detailFeeId">
insert into ar_bill_detail_fee (detail_id, prc_income_bill_fee_id, fee_no, fee_type, fee_name, sc_id, quantity,
unit, unit_price,
amount, product_amount, redline_amount, currency, calculation_formula, round_mode, remark, create_by,
create_time)
values (#{detailId}, #{prcIncomeBillFeeId}, #{feeNo}, #{feeType}, #{feeName}, #{scId}, #{quantity}, #{unit},
#{unitPrice}, #{amount}, #{productAmount}, #{redlineAmount}, #{currency}, #{calculationFormula}, #{roundMode}, #{remark},
#{createBy}, sysdate())
</insert>
<insert id="insertBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="detailFeeId">
insert into ar_bill_detail_fee (
detail_id, prc_income_bill_fee_id, fee_no, fee_type, fee_name, sc_id, quantity, unit, unit_price,
amount, product_amount, redline_amount, currency, calculation_formula, round_mode, remark, create_by, create_time
) values
<foreach collection="list" item="item" separator=",">
(#{item.detailId}, #{item.prcIncomeBillFeeId}, #{item.feeNo}, #{item.feeType}, #{item.feeName},
#{item.scId},
#{item.quantity}, #{item.unit}, #{item.unitPrice}, #{item.amount}, #{item.productAmount}, #{item.redlineAmount}, #{item.currency},
#{item.calculationFormula}, #{item.roundMode}, #{item.remark}, #{item.createBy}, sysdate())
</foreach>
</insert>
<delete id="deleteByBillId" parameterType="long">
delete
f
from ar_bill_detail_fee f
inner join ar_bill_detail d on d.detail_id = f.detail_id
where d.ar_bill_id =
#{arBillId}
</delete>
</mapper>
@@ -0,0 +1,167 @@
<?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.bms.ar.mapper.ArBillDetailMapper">
<!-- 账单明细读写;详情页分页查询,导出任务按游标批量查询。 -->
<resultMap id="ArBillDetailResult" type="ArBillDetail">
<id property="detailId" column="detail_id"/>
<result property="arBillId" column="ar_bill_id"/>
<result property="prcOrderBillId" column="prc_order_bill_id"/>
<result property="detailNo" column="detail_no"/>
<result property="orderNo" column="order_no"/>
<result property="trackingNo" column="tracking_no"/>
<result property="transferNo" column="transfer_no"/>
<result property="receiveTime" column="receive_time"/>
<result property="productCode" column="product_code"/>
<result property="productName" column="product_name"/>
<result property="goodsDescription" column="goods_description"/>
<result property="billingFailStatus" column="billing_fail_status"/>
<result property="countryCode" column="country_code"/>
<result property="countryName" column="country_name"/>
<result property="destPostcode" column="dest_postcode"/>
<result property="actualWeight" column="actual_weight"/>
<result property="receiveWeight" column="receive_weight"/>
<result property="volumeWeight" column="volume_weight"/>
<result property="chargeWeight" column="charge_weight"/>
<result property="freightRate" column="freight_rate"/>
<result property="registrationFee" column="registration_fee"/>
<result property="pkgLength" column="pkg_length"/>
<result property="pkgWidth" column="pkg_width"/>
<result property="pkgHeight" column="pkg_height"/>
<result property="currency" column="currency"/>
<result property="totalAmount" column="total_amount"/>
<result property="productAmount" column="product_amount"/>
<result property="redlineAmount" column="redline_amount"/>
<result property="remark" column="remark"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectByBillId" parameterType="long" resultMap="ArBillDetailResult">
select detail_id, ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time,
product_code, product_name, goods_description, country_code, country_name, dest_postcode,
actual_weight, receive_weight, volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height,
currency, total_amount, product_amount, redline_amount, billing_fail_status, remark, create_by, create_time
from ar_bill_detail where ar_bill_id = #{arBillId} order by detail_no
</select>
<select id="selectByBillIdScoped" resultMap="ArBillDetailResult">
select detail_id, ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time,
product_code, product_name, goods_description, country_code, country_name, dest_postcode,
actual_weight, receive_weight, volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height,
currency, total_amount, product_amount, redline_amount, billing_fail_status, remark, create_by, create_time
from ar_bill_detail where ar_bill_id = #{arBillId} AND EXISTS (SELECT 1 FROM ar_bill b WHERE b.ar_bill_id = ar_bill_detail.ar_bill_id <include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>)
order by detail_no
</select>
<select id="selectByBillIdAndSourceIds" resultMap="ArBillDetailResult">
select detail_id, ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time,
product_code, product_name, goods_description, country_code, country_name, dest_postcode,
actual_weight, receive_weight, volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height,
currency, total_amount, product_amount, redline_amount, billing_fail_status, remark, create_by, create_time
from ar_bill_detail
where ar_bill_id = #{arBillId}
and prc_order_bill_id in
<foreach collection="sourceBillIds" item="sourceBillId" open="(" separator="," close=")">
#{sourceBillId}
</foreach>
order by detail_no
</select>
<resultMap id="ArBillDetailWithFeesResult" type="ArBillDetail" extends="ArBillDetailResult">
<collection property="fees" ofType="ArBillDetailFee">
<id property="detailFeeId" column="fee_detail_id"/>
<result property="detailId" column="fee_parent_detail_id"/>
<result property="prcIncomeBillFeeId" column="fee_prc_income_bill_fee_id"/>
<result property="feeNo" column="fee_no"/>
<result property="feeType" column="fee_type"/>
<result property="feeName" column="fee_name"/>
<result property="scId" column="fee_sc_id"/>
<result property="quantity" column="fee_quantity"/>
<result property="unit" column="fee_unit"/>
<result property="unitPrice" column="fee_unit_price"/>
<result property="amount" column="fee_amount"/>
<result property="productAmount" column="fee_product_amount"/>
<result property="redlineAmount" column="fee_redline_amount"/>
<result property="currency" column="fee_currency"/>
<result property="calculationFormula" column="fee_calculation_formula"/>
<result property="roundMode" column="fee_round_mode"/>
<result property="remark" column="fee_remark"/>
<result property="createBy" column="fee_create_by"/>
<result property="createTime" column="fee_create_time"/>
</collection>
</resultMap>
<select id="selectByBillIdWithFees" parameterType="long" resultMap="ArBillDetailWithFeesResult">
select d.detail_id, d.ar_bill_id, d.prc_order_bill_id, d.detail_no, d.order_no, d.tracking_no, d.transfer_no, d.receive_time,
d.product_code, d.product_name, d.goods_description, d.country_code, d.country_name, d.dest_postcode,
d.actual_weight, d.receive_weight, d.volume_weight, d.charge_weight, d.freight_rate, d.registration_fee, d.pkg_length, d.pkg_width, d.pkg_height,
d.currency, d.total_amount, d.product_amount, d.redline_amount, d.billing_fail_status, d.remark, d.create_by, d.create_time,
f.detail_fee_id as fee_detail_id, f.detail_id as fee_parent_detail_id,
f.prc_income_bill_fee_id as fee_prc_income_bill_fee_id,
f.fee_no, f.fee_type, f.fee_name, f.sc_id as fee_sc_id, f.quantity as fee_quantity,
f.unit as fee_unit, f.unit_price as fee_unit_price, f.amount as fee_amount,
f.product_amount as fee_product_amount, f.redline_amount as fee_redline_amount,
f.currency as fee_currency, f.calculation_formula as fee_calculation_formula,
f.round_mode as fee_round_mode, f.remark as fee_remark, f.create_by as fee_create_by,
f.create_time as fee_create_time
from ar_bill_detail d
left join ar_bill_detail_fee f on f.detail_id = d.detail_id
where d.ar_bill_id = #{arBillId}
order by d.detail_no, d.detail_id, f.fee_no, f.detail_fee_id
</select>
<select id="selectExportPage" resultMap="ArBillDetailResult">
select detail_id, ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time,
product_code, product_name, goods_description, country_code, country_name, dest_postcode,
actual_weight, receive_weight, volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height,
currency, total_amount, product_amount, redline_amount, billing_fail_status, remark, create_by, create_time
from ar_bill_detail
where ar_bill_id = #{arBillId} and detail_no &gt; #{lastDetailNo}
order by detail_no
limit #{pageSize}
</select>
<select id="selectReceiveTimeRangeByBillId" resultType="map">
select min(receive_time) as minReceiveTime, max(receive_time) as maxReceiveTime
from ar_bill_detail
where ar_bill_id = #{arBillId}
</select>
<insert id="insert" parameterType="ArBillDetail" useGeneratedKeys="true" keyProperty="detailId">
insert into ar_bill_detail (ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time,
product_code,
product_name, goods_description, country_code, country_name, dest_postcode,
actual_weight, receive_weight,
volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height, currency,
total_amount, product_amount, redline_amount, billing_fail_status,
remark, create_by, create_time)
values (#{arBillId}, #{prcOrderBillId}, #{detailNo}, #{orderNo}, #{trackingNo}, #{transferNo}, #{receiveTime},
#{productCode}, #{productName}, #{goodsDescription}, #{countryCode}, #{countryName},
#{destPostcode}, #{actualWeight}, #{receiveWeight}, #{volumeWeight}, #{chargeWeight}, #{freightRate}, #{registrationFee}, #{pkgLength}, #{pkgWidth},
#{pkgHeight}, #{currency}, #{totalAmount}, #{productAmount}, #{redlineAmount}, #{billingFailStatus}, #{remark}, #{createBy}, sysdate())
</insert>
<insert id="insertBatch" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="detailId">
insert into ar_bill_detail (
ar_bill_id, prc_order_bill_id, detail_no, order_no, tracking_no, transfer_no, receive_time, product_code,
product_name, goods_description, country_code, country_name, dest_postcode, actual_weight, receive_weight,
volume_weight, charge_weight, freight_rate, registration_fee, pkg_length, pkg_width, pkg_height, currency, total_amount,
product_amount, redline_amount, billing_fail_status,
remark, create_by, create_time
) values
<foreach collection="list" item="item" separator=",">
(#{item.arBillId}, #{item.prcOrderBillId}, #{item.detailNo}, #{item.orderNo}, #{item.trackingNo},
#{item.transferNo}, #{item.receiveTime}, #{item.productCode}, #{item.productName}, #{item.goodsDescription},
#{item.countryCode}, #{item.countryName}, #{item.destPostcode}, #{item.actualWeight}, #{item.receiveWeight},
#{item.volumeWeight}, #{item.chargeWeight}, #{item.freightRate}, #{item.registrationFee}, #{item.pkgLength}, #{item.pkgWidth}, #{item.pkgHeight},
#{item.currency}, #{item.totalAmount}, #{item.productAmount}, #{item.redlineAmount}, #{item.billingFailStatus},
#{item.remark}, #{item.createBy}, sysdate())
</foreach>
</insert>
<delete id="deleteByBillId" parameterType="long">
delete from ar_bill_detail where ar_bill_id = #{arBillId}
</delete>
</mapper>
@@ -0,0 +1,105 @@
<?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.bms.ar.mapper.ArBillExportMapper">
<!-- 导出任务和历史记录;PROCESSING/SUCCESS/FAILED 由异步执行器更新。 -->
<resultMap id="ArBillExportResult" type="ArBillExport">
<id property="exportId" column="export_id"/>
<result property="arBillId" column="ar_bill_id"/>
<result property="fileName" column="file_name"/>
<result property="fileType" column="file_type"/>
<result property="templateId" column="template_id"/>
<result property="templateCode" column="template_code"/>
<result property="templateVersion" column="template_version"/>
<result property="templateStorageType" column="template_storage_type"/>
<result property="templateStorageKey" column="template_storage_key"/>
<result property="templateHash" column="template_hash"/>
<result property="storageKey" column="storage_key"/>
<result property="fileSize" column="file_size"/>
<result property="fileHash" column="file_hash"/>
<result property="rowCount" column="row_count"/>
<result property="exportStatus" column="export_status"/>
<result property="exportUserId" column="export_user_id"/>
<result property="exportBy" column="export_by"/>
<result property="exportTime" column="export_time"/>
<result property="remark" column="remark"/>
</resultMap>
<sql id="selectExportColumns">
select export_id,
ar_bill_id,
file_name,
file_type,
template_id,
template_code,
template_version,
template_storage_type,
template_storage_key,
template_hash,
storage_key,
file_size,
file_hash,
row_count,
export_status,
export_user_id,
export_by,
export_time,
remark
from ar_bill_detail_export
</sql>
<select id="selectByBillId" parameterType="long" resultMap="ArBillExportResult">
<include refid="selectExportColumns"/> where ar_bill_id = #{arBillId} order by export_time desc
</select>
<select id="selectById" parameterType="long" resultMap="ArBillExportResult">
<include refid="selectExportColumns"/> where export_id = #{exportId}
</select>
<select id="selectLatestSuccessByBillId" parameterType="long" resultMap="ArBillExportResult">
<include refid="selectExportColumns"/>
where ar_bill_id = #{arBillId} and export_status = 'SUCCESS'
order by export_time desc limit 1
</select>
<select id="selectProcessingByBillId" parameterType="long" resultMap="ArBillExportResult">
<include refid="selectExportColumns"/>
where ar_bill_id = #{arBillId} and export_status = 'PROCESSING'
order by export_id desc limit 1
</select>
<insert id="insert" parameterType="ArBillExport" useGeneratedKeys="true" keyProperty="exportId">
insert into ar_bill_detail_export (
ar_bill_id, file_name, file_type, template_id, template_code, template_version,
template_storage_type, template_storage_key, template_hash, storage_key,
file_size, file_hash, row_count, export_status, export_user_id, export_by, export_time, remark
) values (
#{arBillId}, #{fileName}, #{fileType}, #{templateId}, #{templateCode}, #{templateVersion},
#{templateStorageType}, #{templateStorageKey}, #{templateHash}, #{storageKey},
#{fileSize}, #{fileHash}, #{rowCount}, #{exportStatus}, #{exportUserId}, #{exportBy}, sysdate(), #{remark}
)
</insert>
<update id="markSuccess" parameterType="ArBillExport">
update ar_bill_detail_export
set storage_key = #{storageKey},
file_size = #{fileSize},
file_hash = #{fileHash},
export_status = 'SUCCESS',
remark = null
where export_id = #{exportId} and export_status = 'PROCESSING'
</update>
<update id="markFailed">
update ar_bill_detail_export
set export_status = 'FAILED', remark = #{remark}
where export_id = #{exportId} and export_status = 'PROCESSING'
</update>
<update id="markExpiredProcessingAsFailed">
update ar_bill_detail_export
set export_status = 'FAILED', remark = #{remark}
where export_status = 'PROCESSING' and export_time &lt; #{expiredBefore}
</update>
</mapper>
@@ -0,0 +1,186 @@
<?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.bms.ar.mapper.ArBillGenerateTaskMapper">
<!-- 生成任务表是异步任务的持久化队列;状态更新均带前置状态条件,保证多节点抢占幂等。 -->
<resultMap id="ArBillGenerateTaskResult" type="ArBillGenerateTask">
<id property="taskId" column="task_id"/>
<result property="taskNo" column="task_no"/>
<result property="arBillId" column="ar_bill_id"/>
<result property="selectionMode" column="selection_mode"/>
<result property="requestPayload" column="request_payload"/>
<result property="snapshotCreateTime" column="snapshot_create_time"/>
<result property="lastSourceBillId" column="last_source_bill_id"/>
<result property="totalCount" column="total_count"/>
<result property="processedCount" column="processed_count"/>
<result property="successCount" column="success_count"/>
<result property="totalAmount" column="total_amount"/>
<result property="status" column="status"/>
<result property="errorMessage" column="error_message"/>
<result property="requestToken" column="request_token"/>
<result property="createBy" column="create_by"/>
<result property="createUserId" column="create_user_id"/>
<result property="createTime" column="create_time"/>
<result property="startedAt" column="started_at"/>
<result property="heartbeatTime" column="heartbeat_time"/>
<result property="finishedAt" column="finished_at"/>
</resultMap>
<sql id="columns">
select task_id,
task_no,
ar_bill_id,
selection_mode,
request_payload,
snapshot_create_time,
last_source_bill_id,
total_count,
processed_count,
success_count,
total_amount,
status,
error_message,
request_token,
create_by,
create_user_id,
create_time,
started_at,
heartbeat_time,
finished_at
from ar_bill_generate_task
</sql>
<select id="selectById" parameterType="long" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where task_id = #{taskId}
</select>
<select id="selectByRequestToken" parameterType="string" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where request_token = #{requestToken}
</select>
<!-- 前端恢复页面时查询当前用户仍需展示的任务。 -->
<select id="selectActiveByCreateBy" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where create_by = #{createBy}
and status in ('WAITING', 'RUNNING', 'CANCEL_REQUESTED')
order by create_time desc, task_id desc
</select>
<select id="selectActiveByCreateByScoped" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where create_by = #{createBy}
and status in ('WAITING', 'RUNNING', 'CANCEL_REQUESTED')
AND EXISTS (SELECT 1 FROM ar_bill b WHERE b.ar_bill_id = ar_bill_generate_task.ar_bill_id
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>)
order by create_time desc, task_id desc
</select>
<!-- 定时调度器按创建时间顺序取待处理任务。 -->
<select id="selectWaiting" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where status = 'WAITING'
order by create_time asc, task_id asc
limit #{limit}
</select>
<insert id="insert" parameterType="ArBillGenerateTask" useGeneratedKeys="true" keyProperty="taskId">
insert into ar_bill_generate_task (task_no, ar_bill_id, selection_mode, request_payload, snapshot_create_time,
last_source_bill_id, total_count, processed_count, success_count,
total_amount,
status, error_message, request_token, create_by, create_user_id, create_time, started_at,
heartbeat_time, finished_at)
values (#{taskNo}, #{arBillId}, #{selectionMode}, #{requestPayload}, #{snapshotCreateTime},
#{lastSourceBillId}, #{totalCount}, #{processedCount}, #{successCount}, #{totalAmount},
#{status}, #{errorMessage}, #{requestToken}, #{createBy}, #{createUserId}, sysdate(), #{startedAt},
#{heartbeatTime}, #{finishedAt})
</insert>
<!-- 条件更新抢占任务;返回 1 才表示当前节点真正拿到执行权。 -->
<update id="markRunning">
update ar_bill_generate_task
set status = 'RUNNING',
started_at = coalesce(started_at, #{startedAt}),
heartbeat_time = #{startedAt}
where task_id = #{taskId}
and status = 'WAITING'
</update>
<update id="updateTotalCount">
update ar_bill_generate_task
set total_count = #{totalCount},
heartbeat_time = sysdate()
where task_id = #{taskId}
and status = 'RUNNING'
</update>
<!-- 每批成功后写入游标、计数和心跳;游标用于故障恢复后继续扫描。 -->
<update id="updateProgress">
update ar_bill_generate_task
set last_source_bill_id = #{lastSourceBillId},
processed_count = #{processedCount},
success_count = #{successCount},
total_amount = #{totalAmount},
heartbeat_time = #{heartbeatTime}
where task_id = #{taskId}
and status = 'RUNNING'
</update>
<update id="markSuccess">
update ar_bill_generate_task
set status = 'SUCCESS',
finished_at = #{finishedAt},
heartbeat_time = #{finishedAt}
where task_id = #{taskId}
and status = 'RUNNING'
</update>
<update id="markFailed">
update ar_bill_generate_task
set status = 'FAILED',
error_message = #{errorMessage},
finished_at = #{finishedAt},
heartbeat_time = #{finishedAt}
where task_id = #{taskId}
and status in ('WAITING', 'RUNNING', 'CANCEL_REQUESTED')
</update>
<update id="markCancelRequested">
update ar_bill_generate_task
set status = 'CANCEL_REQUESTED',
heartbeat_time = sysdate()
where task_id = #{taskId}
and status in ('WAITING', 'RUNNING')
</update>
<update id="markCanceled">
update ar_bill_generate_task
set status = 'CANCELED',
error_message = '用户取消账单生成',
finished_at = #{finishedAt},
heartbeat_time = #{finishedAt}
where task_id = #{taskId}
and status in ('WAITING', 'RUNNING', 'CANCEL_REQUESTED')
</update>
<!-- 执行节点宕机时恢复无心跳的 RUNNING 任务,供调度器重新投递。 -->
<update id="resetExpiredRunning">
update ar_bill_generate_task
set status = 'WAITING',
error_message = '任务执行节点已重启,已自动恢复等待处理',
heartbeat_time = null
where status = 'RUNNING'
and heartbeat_time &lt; #{expiredBefore}
</update>
<!-- 取消请求长时间未完成时由补偿任务取出并执行数据清理。 -->
<select id="selectCancelRequestedBefore" resultMap="ArBillGenerateTaskResult">
<include refid="columns"/>
where status = 'CANCEL_REQUESTED'
and coalesce(heartbeat_time, create_time) &lt; #{expiredBefore}
order by create_time asc, task_id asc
limit #{limit}
</select>
</mapper>
@@ -0,0 +1,95 @@
<?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.bms.ar.mapper.ArBillLogMapper">
<resultMap id="ArBillLogResult" type="ArBillLog">
<id property="logId" column="log_id"/>
<result property="arBillId" column="ar_bill_id"/>
<result property="objectType" column="object_type"/>
<result property="objectId" column="object_id"/>
<result property="objectDisplay" column="object_display"/>
<result property="operationType" column="operation_type"/>
<result property="operationDesc" column="operation_desc"/>
<result property="fromStatus" column="from_status"/>
<result property="toStatus" column="to_status"/>
<result property="beforeData" column="before_data"/>
<result property="afterData" column="after_data"/>
<result property="operatorId" column="operator_id"/>
<result property="operatorName" column="operator_name"/>
<result property="operationSource" column="operation_source"/>
<result property="requestId" column="request_id"/>
<result property="traceId" column="trace_id"/>
<result property="result" column="result"/>
<result property="errorMessage" column="error_message"/>
<result property="clientIp" column="client_ip"/>
<result property="createTime" column="create_time"/>
</resultMap>
<select id="selectList" resultMap="ArBillLogResult">
select l.log_id, l.ar_bill_id, l.object_type, l.object_id, l.operation_type, l.operation_desc,
case l.object_type
when 'BILL' then b.bill_no
when 'EXPORT' then coalesce(e.file_name, b.bill_no)
when 'BALANCE_WRITEOFF' then bw.writeoff_no
else null
end as object_display,
l.from_status, l.to_status, l.before_data, l.after_data, l.operator_id, l.operator_name,
l.operation_source, l.request_id, l.trace_id, l.result, l.error_message, l.client_ip, l.create_time
from ar_bill_log l
left join ar_bill b on b.ar_bill_id = l.ar_bill_id
left join ar_bill_detail_export e on e.export_id = case when l.object_type = 'EXPORT' then cast(l.object_id as
unsigned) end
left join ar_balance_writeoff bw on bw.writeoff_id = case when l.object_type = 'BALANCE_WRITEOFF' then
cast(l.object_id as unsigned) end
<where>
<if test="query.arBillId != null">and l.ar_bill_id = #{query.arBillId}</if>
<if test="query.objectType != null and query.objectType != ''">and l.object_type = #{query.objectType}</if>
<if test="query.objectId != null and query.objectId != ''">and l.object_id = #{query.objectId}</if>
<if test="query.operationType != null and query.operationType != ''">and l.operation_type = #{query.operationType}</if>
<if test="query.operationSource != null and query.operationSource != ''">and l.operation_source = #{query.operationSource}
</if>
<if test="query.requestId != null and query.requestId != ''">and l.request_id = #{query.requestId}</if>
<if test="query.result != null and query.result != ''">and l.result = #{query.result}</if>
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>
</where>
order by l.create_time desc, l.log_id desc
</select>
<select id="selectSuccessByRequestId" resultMap="ArBillLogResult">
select log_id,
ar_bill_id,
object_type,
object_id,
operation_type,
operation_desc,
from_status,
to_status,
before_data,
after_data,
operator_id,
operator_name,
operation_source,
request_id,
trace_id,
result,
error_message,
client_ip,
create_time
from ar_bill_log
where request_id = #{requestId}
and object_type = #{objectType}
and result = #{result}
order by log_id limit 1
</select>
<insert id="insert" parameterType="ArBillLog" useGeneratedKeys="true" keyProperty="logId">
insert into ar_bill_log (ar_bill_id, object_type, object_id, operation_type, operation_desc, from_status,
to_status,
before_data, after_data, operator_id, operator_name, operation_source, request_id,
trace_id, result, error_message, client_ip, create_time)
values (#{arBillId}, #{objectType}, #{objectId}, #{operationType}, #{operationDesc}, #{fromStatus}, #{toStatus},
#{beforeData}, #{afterData}, #{operatorId}, #{operatorName}, #{operationSource}, #{requestId},
#{traceId}, #{result}, #{errorMessage}, #{clientIp}, sysdate())
</insert>
</mapper>
@@ -0,0 +1,240 @@
<?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.bms.ar.mapper.ArBillMapper">
<!-- 账单头查询、状态流转和金额/生成进度更新。带 ForUpdate 的查询用于核销并发控制。 -->
<resultMap id="ArBillResult" type="ArBill">
<id property="arBillId" column="ar_bill_id"/>
<result property="billNo" column="bill_no"/>
<result property="billName" column="bill_name"/>
<result property="customerId" column="customer_id"/>
<result property="customerCode" column="customer_code"/>
<result property="customerName" column="customer_name"/>
<result property="profitCustomerArea" column="profit_customer_area"/>
<result property="profitSalesUserId" column="profit_sales_user_id"/>
<result property="profitSalesUserCode" column="profit_sales_user_code"/>
<result property="profitSalesUserName" column="profit_sales_user_name"/>
<result property="billPeriodStart" column="bill_period_start"/>
<result property="billPeriodEnd" column="bill_period_end"/>
<result property="billDate" column="bill_date"/>
<result property="currency" column="currency"/>
<result property="orderCount" column="order_count"/>
<result property="totalAmount" column="total_amount"/>
<result property="writtenOffAmount" column="written_off_amount"/>
<result property="unwrittenAmount" column="unwritten_amount"/>
<result property="status" column="status"/>
<result property="generationStatus" column="generation_status"/>
<result property="billVersion" column="bill_version"/>
<result property="bankAccountName" column="bank_account_name"/>
<result property="bankAccountNo" column="bank_account_no"/>
<result property="bankName" column="bank_name"/>
<result property="remark" column="remark"/>
<result property="confirmedBy" column="confirmed_by"/>
<result property="confirmedTime" column="confirmed_time"/>
<result property="createBy" column="create_by"/>
<result property="createUserId" column="create_user_id"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
</resultMap>
<resultMap id="ArBillSummaryResult" type="com.bms.receivable.domain.vo.ArBillSummary">
<result property="totalAmount" column="total_amount"/>
<result property="writtenOffAmount" column="written_off_amount"/>
<result property="unwrittenAmount" column="unwritten_amount"/>
</resultMap>
<sql id="selectArBillColumns">
select ar_bill_id,
bill_no,
bill_name,
customer_id,
customer_code,
customer_name,
profit_customer_area,
profit_sales_user_id,
profit_sales_user_code,
profit_sales_user_name,
bill_period_start,
bill_period_end,
bill_date,
currency,
order_count,
total_amount,
written_off_amount,
unwritten_amount,
status,
generation_status,
bill_version,
bank_account_name,
bank_account_no,
bank_name,
remark,
confirmed_by,
confirmed_time,
create_by,
create_user_id,
create_time,
update_by,
update_time
from ar_bill
</sql>
<sql id="arBillListFilter">
<where>
and (generation_status is null or generation_status = 'READY')
<if test="query.billNo != null and query.billNo != ''">and bill_no like concat('%', #{query.billNo}, '%')</if>
<if test="query.billName != null and query.billName != ''">and bill_name like concat('%', #{query.billName}, '%')</if>
<if test="query.customerCode != null and query.customerCode != ''">and customer_code like concat('%', #{query.customerCode},
'%')
</if>
<if test="query.customerName != null and query.customerName != ''">and customer_name like concat('%', #{query.customerName},
'%')
</if>
<if test="query.customerId != null">and customer_id = #{query.customerId}</if>
<choose>
<when test="query.statuses != null and query.statuses.size() > 0">
and status in
<foreach collection="query.statuses" item="statusValue" open="(" separator="," close=")">
#{statusValue}
</foreach>
</when>
<when test="query.status != null and query.status != ''">and status = #{query.status}</when>
</choose>
<if test="query.currency != null and query.currency != ''">and currency = #{query.currency}</if>
<if test="query.billDateStart != null">and bill_date &gt;= #{query.billDateStart}</if>
<if test="query.billDateEnd != null">and bill_date &lt;= #{query.billDateEnd}</if>
<if test="query.billPeriodEnd != null">and bill_period_end = #{query.billPeriodEnd}</if>
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>
</where>
</sql>
<select id="selectArBillList" resultMap="ArBillResult">
select b.* from ar_bill b
<include refid="arBillListFilter"/>
order by create_time desc, ar_bill_id desc
</select>
<select id="selectArBillSummary" resultMap="ArBillSummaryResult">
select coalesce(sum(total_amount), 0) as total_amount,
coalesce(sum(written_off_amount), 0) as written_off_amount,
coalesce(sum(unwritten_amount), 0) as unwritten_amount
from ar_bill b
<include refid="arBillListFilter"/>
and status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF')
</select>
<select id="selectArBillById" parameterType="long" resultMap="ArBillResult">
<include refid="selectArBillColumns"/>
where ar_bill_id = #{arBillId}
</select>
<select id="selectArBillByIdScoped" resultMap="ArBillResult">
select b.* from ar_bill b where b.ar_bill_id = #{arBillId}
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>
</select>
<select id="selectArBillByBillNo" parameterType="string" resultMap="ArBillResult">
<include refid="selectArBillColumns"/>
where bill_no = #{billNo}
</select>
<select id="selectGeneratingByCustomerPeriod" resultMap="ArBillResult">
<include refid="selectArBillColumns"/>
where customer_id = #{customerId}
and currency = #{currency}
and bill_period_end = #{cutoffDate}
and generation_status = 'GENERATING'
order by ar_bill_id desc
limit 1
</select>
<select id="selectMaxBillVersion" resultType="int">
select bill_version
from ar_bill
where customer_id = #{customerId}
and bill_period_end = #{cutoffDate}
and currency = #{currency}
order by bill_version desc limit 1
for
update
</select>
<select id="selectArBillByIdForUpdate" parameterType="long" resultMap="ArBillResult">
<include refid="selectArBillColumns"/>
where ar_bill_id = #{arBillId} for update
</select>
<select id="selectUnsettledByCustomer" resultMap="ArBillResult">
select b.* from ar_bill b
where customer_id = #{customerId}
and status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF')
and (generation_status is null or generation_status = 'READY')
and unwritten_amount &gt; 0
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.billScope"/>
order by bill_date asc, ar_bill_id asc
</select>
<insert id="insertArBill" parameterType="ArBill" useGeneratedKeys="true" keyProperty="arBillId">
insert into ar_bill (bill_no, bill_name, customer_id, customer_code, customer_name,
profit_customer_area, profit_sales_user_id, profit_sales_user_code, profit_sales_user_name, bill_period_start,
bill_period_end,
bill_date, currency, order_count, total_amount, written_off_amount, unwritten_amount,
status, generation_status, bill_version, bank_account_name, bank_account_no, bank_name,
remark,
confirmed_by, confirmed_time, create_by, create_user_id, create_time, update_by, update_time)
values (#{billNo}, #{billName}, #{customerId}, #{customerCode}, #{customerName},
#{profitCustomerArea}, #{profitSalesUserId}, #{profitSalesUserCode}, #{profitSalesUserName}, #{billPeriodStart},
#{billPeriodEnd},
#{billDate}, #{currency}, #{orderCount}, #{totalAmount}, #{writtenOffAmount}, #{unwrittenAmount},
#{status}, #{generationStatus}, #{billVersion}, #{bankAccountName}, #{bankAccountNo}, #{bankName},
#{remark},
#{confirmedBy}, #{confirmedTime}, #{createBy}, #{createUserId}, sysdate(), #{updateBy}, sysdate())
</insert>
<update id="updateArBillStatus">
update ar_bill
set status = #{status},
remark = #{remark},
update_by = #{operator},
update_time = sysdate(),
confirmed_by = case when #{status} = 'CONFIRMED' then #{operator} else confirmed_by end,
confirmed_time = case when #{status} = 'CONFIRMED' then sysdate() else confirmed_time end
where ar_bill_id = #{arBillId}
and status = #{fromStatus}
</update>
<update id="updateArBillAmounts">
update ar_bill
set written_off_amount = #{writtenOffAmount},
unwritten_amount = #{unwrittenAmount},
status = #{status},
update_by = #{operator},
update_time = sysdate()
where ar_bill_id = #{arBillId}
and status = #{fromStatus}
</update>
<update id="updateArBillProgress">
update ar_bill
set order_count = #{orderCount},
total_amount = #{totalAmount},
unwritten_amount = #{unwrittenAmount},
bill_period_start = case
when #{billPeriodStart} &lt; bill_period_start then #{billPeriodStart}
else bill_period_start end,
update_by = #{operator},
update_time = sysdate()
where ar_bill_id = #{arBillId}
</update>
<update id="updateArBillGenerationStatus">
update ar_bill
set generation_status = #{generationStatus},
update_by = #{operator},
update_time = sysdate(),
remark = case when #{remark} is null or #{remark} = '' then remark else #{remark} end
where ar_bill_id = #{arBillId}
</update>
</mapper>
@@ -0,0 +1,63 @@
<?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.bms.ar.mapper.ArBillScopeMapper">
<resultMap id="CustomerOption" type="com.bms.customer.customerinfo.domain.BmsCustomerOption">
<id property="customerId" column="customer_id"/>
<result property="customerCode" column="customer_code"/>
<result property="customerName" column="customer_name"/>
</resultMap>
<select id="countCustomerSourceBills" resultType="int">
SELECT COUNT(*) FROM prc_order_bill WHERE customer_id = #{customerId}
AND bill_id IN
<foreach collection="sourceIds" item="sourceId" open="(" separator="," close=")">#{sourceId}</foreach>
</select>
<!-- c 固定为客户表别名;无部门层级扩展,不按角色管理 data_scope 过滤。 -->
<sql id="customerScope">
<choose>
<when test="scope != null and scope.all"/>
<when test="scope != null and (scope.self or scope.department)">
AND c.del_flag = '0'
AND EXISTS (
SELECT 1 FROM sys_user su
WHERE CAST(su.user_id AS CHAR) = c.sales_user_id AND su.del_flag = '0'
AND (1 = 0
<if test="scope.self">OR su.user_id = #{scope.userId}</if>
<if test="scope.department">OR su.dept_id = #{scope.deptId}</if>
)
)
</when>
<otherwise>AND 1 = 0</otherwise>
</choose>
</sql>
<!-- b 固定为账单表别名;ALL 无需关联客户,保留归属异常的历史账单。 -->
<sql id="billScope">
<choose>
<when test="scope != null and scope.all"/>
<otherwise>
AND EXISTS (SELECT 1 FROM ctr_customer c WHERE c.customer_id = b.customer_id
<include refid="com.bms.receivable.mapper.ArBillScopeMapper.customerScope"/>
)
</otherwise>
</choose>
</sql>
<select id="countAccessibleBill" resultType="int">
SELECT COUNT(*) FROM ar_bill b WHERE b.ar_bill_id = #{arBillId}
<include refid="billScope"/>
</select>
<select id="selectAccessibleCustomer" resultMap="CustomerOption">
SELECT c.customer_id, c.customer_code, c.customer_name FROM ctr_customer c
WHERE c.customer_id = #{customerId} AND c.del_flag = '0'
<include refid="customerScope"/>
</select>
<select id="selectCustomerOptions" resultMap="CustomerOption">
SELECT c.customer_id, c.customer_code, c.customer_name FROM ctr_customer c WHERE c.del_flag = '0'
<include refid="customerScope"/>
<if test="keywords != null and !keywords.isEmpty()">
AND (<foreach collection="keywords" item="keyword" separator=" OR ">
(c.customer_name LIKE CONCAT('%', #{keyword}, '%') OR c.customer_code LIKE CONCAT('%', #{keyword}, '%')
OR c.customer_code_dw LIKE CONCAT('%', #{keyword}, '%'))
</foreach>)
</if>
ORDER BY c.customer_id DESC
</select>
</mapper>
@@ -0,0 +1,189 @@
<?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.bms.ar.mapper.ArCommissionMapper">
<resultMap id="rate" type="com.bms.receivable.profit.ArCommissionRate">
<id property="rateId" column="rate_id"/><result property="salesUserId" column="sales_user_id"/>
<result property="salesUserCode" column="sales_user_code"/><result property="salesUserName" column="sales_user_name"/>
<result property="rate" column="rate"/><result property="effectiveAt" column="effective_at"/>
<result property="createBy" column="create_by"/><result property="remark" column="remark"/>
</resultMap>
<resultMap id="missingRate" type="com.bms.receivable.profit.ArWriteoffRate">
<id property="writeoffId" column="writeoff_id"/><result property="arBillId" column="ar_bill_id"/>
<result property="billNo" column="bill_no"/><result property="customerName" column="customer_name"/>
<result property="salesUserId" column="sales_user_id"/><result property="salesUserName" column="sales_user_name"/>
<result property="writeoffAmount" column="writeoff_amount"/><result property="writeoffDate" column="writeoff_date"/>
<result property="rate" column="rate"/>
<result property="status" column="status"/><result property="confirmedBy" column="confirmed_by"/>
<result property="confirmedTime" column="confirmed_time"/><result property="remark" column="confirm_remark"/>
</resultMap>
<resultMap id="commissionResult" type="com.bms.receivable.profit.ArCommissionResult">
<id property="resultId" column="result_id"/><result property="arBillId" column="ar_bill_id"/>
<result property="detailId" column="detail_id"/><result property="billNo" column="bill_no"/>
<result property="orderNo" column="order_no"/><result property="salesUserName" column="sales_user_name"/>
<result property="currency" column="currency"/><result property="grossProfit" column="gross_profit"/>
<result property="commissionAmount" column="commission_amount"/><result property="resultStatus" column="result_status"/>
<result property="createTime" column="create_time"/>
<result property="reversedBy" column="reversed_by"/><result property="reversedTime" column="reversed_time"/>
<result property="salesUserId" column="sales_user_id"/><result property="weightedRate" column="weighted_rate"/>
<result property="billAmount" column="bill_amount"/>
</resultMap>
<resultMap id="commissionSummary" type="com.bms.receivable.profit.ArCommissionSummary">
<result property="salesUserId" column="sales_user_id"/><result property="salesUserName" column="sales_user_name"/>
<result property="currency" column="currency"/><result property="orderCount" column="order_count"/>
<result property="pendingCount" column="pending_count"/><result property="commissionAmount" column="commission_amount"/>
</resultMap>
<select id="selectRates" resultMap="rate">
select r.rate_id, r.sales_user_id, u.user_name as sales_user_code, u.nick_name as sales_user_name,
r.rate, r.effective_at, r.create_by, r.remark
from ar_profit_commission_rate r left join sys_user u on u.user_id = r.sales_user_id
order by r.sales_user_id, r.effective_at desc, r.rate_id desc
</select>
<select id="selectEffective" resultMap="rate">
select rate_id, sales_user_id, rate, effective_at
from ar_profit_commission_rate
where sales_user_id = #{salesUserId} and effective_at &lt;= #{at}
order by effective_at desc, rate_id desc limit 1 for update
</select>
<insert id="insertRate" parameterType="com.bms.receivable.profit.ArCommissionRate" useGeneratedKeys="true" keyProperty="rateId">
insert into ar_profit_commission_rate(sales_user_id, rate, effective_at, create_by, create_time, remark)
values(#{salesUserId}, #{rate}, #{effectiveAt}, #{createBy}, sysdate(), #{remark})
</insert>
<select id="lockSalesUser" resultType="long">
select user_id from sys_user where user_id = #{salesUserId} for update
</select>
<insert id="insertWriteoffRate">
insert into ar_profit_writeoff_rate(writeoff_id, sales_user_id, rate_id, rate, create_time)
values(#{writeoffId}, #{salesUserId}, #{rateId}, #{rate}, sysdate())
</insert>
<select id="selectMissingRates" resultMap="missingRate">
select w.writeoff_id, b.ar_bill_id, b.bill_no, b.customer_name,
b.profit_sales_user_id as sales_user_id, b.profit_sales_user_name as sales_user_name,
w.writeoff_amount, w.writeoff_date, r.rate
from ar_balance_writeoff w join ar_bill b on b.ar_bill_id = w.ar_bill_id
left join ar_profit_writeoff_rate r on r.writeoff_id = w.writeoff_id
where w.status = 'EFFECTIVE' and (r.rate is null or r.rate &lt; 0 or r.rate > 100)
and b.status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF')
and b.generation_status = 'READY'
order by w.writeoff_date desc, w.writeoff_id desc
</select>
<select id="selectWriteoffRates" resultMap="missingRate">
select w.writeoff_id, b.ar_bill_id, b.bill_no, b.customer_name,
b.profit_sales_user_id as sales_user_id, b.profit_sales_user_name as sales_user_name,
w.writeoff_amount, w.writeoff_date, w.status, r.rate, r.confirmed_by, r.confirmed_time, r.confirm_remark
from ar_balance_writeoff w join ar_bill b on b.ar_bill_id = w.ar_bill_id
left join ar_profit_writeoff_rate r on r.writeoff_id = w.writeoff_id
where b.ar_bill_id = #{billId} and b.generation_status = 'READY'
and b.status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF')
order by w.create_time, w.writeoff_id
</select>
<select id="selectBillIdByWriteoffId" resultType="long">
select ar_bill_id from ar_balance_writeoff where writeoff_id = #{writeoffId} and status = 'EFFECTIVE'
</select>
<select id="countMissingRates" resultType="int">
select count(*) from ar_balance_writeoff w
left join ar_profit_writeoff_rate r on r.writeoff_id = w.writeoff_id
where w.ar_bill_id = #{billId} and w.status = 'EFFECTIVE' and (r.rate is null or r.rate &lt; 0 or r.rate > 100)
</select>
<update id="confirmMissingRate">
update ar_profit_writeoff_rate r
join ar_balance_writeoff w on w.writeoff_id = r.writeoff_id and w.status = 'EFFECTIVE'
join ar_bill b on b.ar_bill_id = w.ar_bill_id
set r.sales_user_id = b.profit_sales_user_id, r.rate = #{rate}, r.confirmed_by = #{operator},
r.confirmed_time = sysdate(), r.confirm_remark = #{remark}
where r.writeoff_id = #{writeoffId} and r.rate is null and b.profit_sales_user_id is not null
</update>
<select id="selectResults" resultMap="commissionResult">
select r.result_id, r.ar_bill_id, r.detail_id, b.bill_no, d.order_no,
b.profit_sales_user_name as sales_user_name, r.currency, r.gross_profit,
r.commission_amount, r.result_status, r.create_time, r.reversed_by, r.reversed_time
from ar_profit_commission_result r join ar_bill b on b.ar_bill_id = r.ar_bill_id
join ar_bill_detail d on d.detail_id = r.detail_id
where 1 = 1
<choose>
<when test="includeReversed">and (r.result_status = 'REVERSED' or (b.status = 'WRITTEN_OFF' and b.generation_status = 'READY'))</when>
<otherwise>and r.result_status != 'REVERSED' and b.status = 'WRITTEN_OFF' and b.generation_status = 'READY'</otherwise>
</choose>
<if test="billId != null">and r.ar_bill_id = #{billId}</if>
<include refid="com.bms.receivable.mapper.ArProfitMapper.scopeCondition"/>
order by r.result_id desc
</select>
<select id="selectCommissionSummary" resultMap="commissionSummary">
select r.sales_user_id, max(b.profit_sales_user_name) as sales_user_name, r.currency,
count(*) as order_count,
sum(case when r.result_status != 'READY' then 1 else 0 end) as pending_count,
<choose>
<when test="billId != null">
case when sum(case when r.result_status != 'READY' then 1 else 0 end) > 0 then null
else sum(case when r.result_status = 'READY' then r.commission_amount else null end) end
</when>
<otherwise>sum(case when r.result_status = 'READY' then r.commission_amount else null end)</otherwise>
</choose> as commission_amount
from ar_profit_commission_result r join ar_bill b on b.ar_bill_id = r.ar_bill_id
where r.result_status != 'REVERSED' and b.status = 'WRITTEN_OFF' and b.generation_status = 'READY'
<if test="billId != null">and r.ar_bill_id = #{billId}</if>
<include refid="com.bms.receivable.mapper.ArProfitMapper.scopeCondition"/>
group by r.sales_user_id, r.currency
order by sales_user_name, r.currency
</select>
<update id="reverseResults">
update ar_profit_commission_result
set result_status = 'REVERSED', reversed_by = #{operator}, reversed_time = sysdate()
where ar_bill_id = #{billId} and result_status != 'REVERSED'
</update>
<!-- 当且仅当账单全部核销时,以当次费用快照及每笔有效核销的比例生成正式记录。 -->
<select id="selectSettlementInputs" resultMap="commissionResult">
<bind name="shenzhenArea" value="@com.bms.price.enums.ProfitAreaRule@SHENZHEN.getCustomerArea()"/>
<bind name="guangzhouArea" value="@com.bms.price.enums.ProfitAreaRule@GUANGZHOU.getCustomerArea()"/>
select x.ar_bill_id, x.detail_id, x.profit_sales_user_id as sales_user_id, x.currency, x.gross_profit,
x.weighted_rate, x.total_amount as bill_amount, coalesce(x.issue, 'READY') as result_status
from (
select b.ar_bill_id, d.detail_id, b.profit_sales_user_id, d.currency, b.total_amount, w.weighted_rate,
case when f.currency_count = 1 and f.fee_currency = d.currency and d.currency = b.currency and f.sales_amount = d.total_amount and b.profit_customer_area = #{shenzhenArea} and f.product_complete = 1
then f.sales_amount - f.product_amount
when f.currency_count = 1 and f.fee_currency = d.currency and d.currency = b.currency and f.sales_amount = d.total_amount and b.profit_customer_area = #{guangzhouArea} and f.redline_complete = 1
then f.sales_amount - f.redline_amount else null end as gross_profit,
case when b.profit_sales_user_id is null or b.profit_customer_area is null
or b.profit_customer_area not in (#{shenzhenArea},#{guangzhouArea}) then 'MISSING_SNAPSHOT'
when w.bill_id is null or w.written_amount != b.total_amount then 'WRITEOFF_MISMATCH'
when w.missing_rates > 0 then 'MISSING_RATE'
when b.total_amount is null or b.total_amount &lt;= 0 or d.total_amount is null
or d.currency is null or b.currency is null or f.sales_amount is null
or f.currency_count != 1 or f.fee_currency != d.currency or d.currency != b.currency
or f.sales_amount != d.total_amount
or (b.profit_customer_area = #{shenzhenArea} and coalesce(f.product_complete, 0) = 0)
or (b.profit_customer_area = #{guangzhouArea} and coalesce(f.redline_complete, 0) = 0)
then 'MISSING_PRICE'
else null end as issue
from ar_bill b inner join ar_bill_detail d on d.ar_bill_id = b.ar_bill_id
left join (
select fee.detail_id, case when count(fee.amount) = count(*) then sum(fee.amount) else null end as sales_amount,
case when count(fee.currency) = count(*) then count(distinct fee.currency) else 0 end as currency_count, min(fee.currency) as fee_currency,
case when count(fee.product_amount) = count(*) then sum(fee.product_amount) else null end as product_amount,
case when count(fee.redline_amount) = count(*) then sum(fee.redline_amount) else null end as redline_amount,
case when count(fee.product_amount) = count(*) then 1 else 0 end as product_complete,
case when count(fee.redline_amount) = count(*) then 1 else 0 end as redline_complete
from ar_bill_detail_fee fee join ar_bill_detail detail on detail.detail_id = fee.detail_id
where detail.ar_bill_id = #{billId} group by fee.detail_id
) f on f.detail_id = d.detail_id
left join (
select w.ar_bill_id as bill_id, sum(w.writeoff_amount) as written_amount,
sum(case when r.rate is null or r.rate &lt; 0 or r.rate > 100 then 1 else 0 end) as missing_rates,
sum(w.writeoff_amount * r.rate) as weighted_rate
from ar_balance_writeoff w left join ar_profit_writeoff_rate r on r.writeoff_id = w.writeoff_id
where w.status = 'EFFECTIVE' and w.ar_bill_id = #{billId}
group by w.ar_bill_id
) w on w.bill_id = b.ar_bill_id
where b.ar_bill_id = #{billId} and b.status = 'WRITTEN_OFF' and b.generation_status = 'READY'
) x order by x.detail_id
</select>
<insert id="insertResults">
insert into ar_profit_commission_result
(ar_bill_id, detail_id, sales_user_id, currency, gross_profit, commission_amount, result_status, create_by, create_time)
values
<foreach collection="items" item="item" separator=",">
(#{item.arBillId}, #{item.detailId}, #{item.salesUserId}, #{item.currency}, #{item.grossProfit},
#{item.commissionAmount}, #{item.resultStatus}, #{operator}, sysdate())
</foreach>
</insert>
</mapper>
@@ -0,0 +1,45 @@
<?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.bms.ar.mapper.ArExportTemplateMapper">
<!-- 模板管理查询;导出提交时会把选中的模板版本快照到导出任务。 -->
<resultMap id="ArExportTemplateResult" type="ArExportTemplate">
<id property="templateId" column="template_id"/>
<result property="templateCode" column="template_code"/>
<result property="templateName" column="template_name"/>
<result property="businessType" column="business_type"/>
<result property="templateVersion" column="template_version"/>
<result property="storageType" column="storage_type"/>
<result property="storageKey" column="storage_key"/>
<result property="fileHash" column="file_hash"/>
<result property="status" column="status"/>
<result property="isDefault" column="is_default"/>
<result property="effectiveStart" column="effective_start"/>
<result property="effectiveEnd" column="effective_end"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectDefaultEnabled" resultMap="ArExportTemplateResult">
select template_id,
template_code,
template_name,
business_type,
template_version,
storage_type,
storage_key,
file_hash,
status,
is_default,
effective_start,
effective_end,
remark
from ar_export_template
where business_type = #{businessType}
and status = 'ENABLED'
and is_default = '1'
and (effective_start is null or effective_start &lt;= #{effectiveDate})
and (effective_end is null or effective_end &gt;= #{effectiveDate})
order by effective_start desc, template_id desc limit 1
</select>
</mapper>
@@ -0,0 +1,164 @@
<?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.bms.ar.mapper.ArProfitMapper">
<resultMap id="row" type="com.bms.receivable.profit.ArProfitRow">
<id property="arBillId" column="ar_bill_id"/>
<result property="billNo" column="bill_no"/><result property="billName" column="bill_name"/>
<result property="billDate" column="bill_date"/>
<result property="customerCode" column="customer_code"/><result property="customerName" column="customer_name"/>
<result property="customerArea" column="customer_area"/>
<result property="salesUserName" column="sales_user_name"/><result property="currency" column="currency"/>
<result property="status" column="status"/><result property="salesAmount" column="sales_amount"/>
<result property="productAmount" column="product_amount"/><result property="salesGrossProfit" column="sales_gross_profit"/>
<result property="salesGrossMarginRate" column="sales_gross_margin_rate"/>
<result property="writtenOffAmount" column="written_off_amount"/><result property="unwrittenAmount" column="unwritten_amount"/>
</resultMap>
<resultMap id="summary" type="com.bms.receivable.profit.ArProfitSummary">
<result property="currency" column="currency"/><result property="billCount" column="bill_count"/>
<result property="salesAmount" column="sales_amount"/><result property="productAmount" column="product_amount"/>
<result property="salesGrossProfit" column="sales_gross_profit"/><result property="salesGrossMarginRate" column="sales_gross_margin_rate"/>
<result property="commissionAmount" column="commission_amount"/>
<result property="writtenOffAmount" column="written_off_amount"/><result property="unwrittenAmount" column="unwritten_amount"/>
</resultMap>
<resultMap id="detail" type="com.bms.receivable.domain.ArBillDetail">
<id property="detailId" column="detail_id"/><result property="orderNo" column="order_no"/>
<result property="productName" column="product_name"/><result property="currency" column="currency"/>
<result property="totalAmount" column="total_amount"/>
</resultMap>
<resultMap id="fee" type="com.bms.receivable.domain.ArBillDetailFee">
<id property="detailFeeId" column="detail_fee_id"/><result property="detailId" column="detail_id"/>
<result property="feeName" column="fee_name"/><result property="feeType" column="fee_type"/>
<result property="amount" column="amount"/><result property="productAmount" column="product_amount"/>
<result property="redlineAmount" column="redline_amount"/><result property="currency" column="currency"/>
</resultMap>
<sql id="scopeCondition">
<choose>
<when test="scope.all"/>
<when test="scope.self or scope.department">
and (1 = 0
<if test="scope.self">or b.profit_sales_user_id = #{scope.userId}</if>
<if test="scope.department">
or exists (select 1 from sys_user u inner join sys_dept dept on dept.dept_id = u.dept_id
where u.user_id = b.profit_sales_user_id and u.del_flag = '0'
and (dept.dept_id = #{scope.deptId} or find_in_set(#{scope.deptId}, dept.ancestors)))
</if>
)
</when>
<otherwise>and 1 = 0</otherwise>
</choose>
</sql>
<sql id="billConditions">
where b.status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF') and b.generation_status = 'READY'
<include refid="scopeCondition"/>
<if test="query.customerId != null">and b.customer_id = #{query.customerId}</if>
<if test="query.billNo != null and query.billNo != ''">and b.bill_no like concat('%', #{query.billNo}, '%')</if>
<if test="query.arBillId != null">and b.ar_bill_id = #{query.arBillId}</if>
<if test="query.status != null and query.status != ''">and b.status = #{query.status}</if>
<if test="query.salesUserId != null">and b.profit_sales_user_id = #{query.salesUserId}</if>
<if test="query.beginBillDate != null">and b.bill_date &gt;= #{query.beginBillDate}</if>
<if test="query.endBillDate != null">and b.bill_date &lt;= #{query.endBillDate}</if>
</sql>
<!-- 按费用快照先聚合到订单,再聚合到完整账单,避免账单金额及费用重复。 -->
<sql id="billRows">
<bind name="shenzhenArea" value="@com.bms.price.enums.ProfitAreaRule@SHENZHEN.getCustomerArea()"/>
<bind name="guangzhouArea" value="@com.bms.price.enums.ProfitAreaRule@GUANGZHOU.getCustomerArea()"/>
select b.ar_bill_id, b.bill_no, b.bill_name, b.bill_date, b.customer_code, b.customer_name,
b.profit_customer_area as customer_area,
b.profit_sales_user_name as sales_user_name, b.currency, b.status,
b.total_amount as sales_amount, b.written_off_amount, b.unwritten_amount,
case when a.detail_count > 0 and a.invalid_count = 0 and b.total_amount is not null
and a.detail_total = b.total_amount then a.product_total else null end as product_amount,
case when a.detail_count > 0 and a.invalid_count = 0 and b.total_amount is not null
and a.detail_total = b.total_amount then b.total_amount - a.product_total else null end as sales_gross_profit,
case when a.detail_count > 0 and a.invalid_count = 0 and b.total_amount is not null
and a.detail_total = b.total_amount and b.total_amount != 0
then round((b.total_amount - a.product_total) * 100 / b.total_amount, 4) else null end as sales_gross_margin_rate,
case when a.detail_count > 0 and a.invalid_count = 0 and b.total_amount is not null
and a.detail_total = b.total_amount then 0 else 1 end as profit_incomplete
from ar_bill b
left join (
select d.ar_bill_id, count(*) as detail_count, sum(d.total_amount) as detail_total,
sum(case when d.total_amount is not null and d.currency is not null and b.currency is not null
and d.currency = b.currency and f.currency_count = 1 and f.fee_currency = d.currency
and f.sales_amount is not null and f.sales_amount = d.total_amount
and ((b.profit_customer_area = #{shenzhenArea} and f.product_complete = 1)
or (b.profit_customer_area = #{guangzhouArea} and f.redline_complete = 1))
then 0 else 1 end) as invalid_count,
sum(case when b.profit_customer_area = #{shenzhenArea} then f.product_amount
when b.profit_customer_area = #{guangzhouArea} then f.redline_amount else null end) as product_total
from ar_bill_detail d join ar_bill b on b.ar_bill_id = d.ar_bill_id
left join (
select fee.detail_id,
case when count(fee.amount) = count(*) then sum(fee.amount) else null end as sales_amount,
case when count(fee.currency) = count(*) then count(distinct fee.currency) else 0 end as currency_count,
min(fee.currency) as fee_currency,
case when count(fee.product_amount) = count(*) then sum(fee.product_amount) else null end as product_amount,
case when count(fee.redline_amount) = count(*) then sum(fee.redline_amount) else null end as redline_amount,
case when count(fee.product_amount) = count(*) then 1 else 0 end as product_complete,
case when count(fee.redline_amount) = count(*) then 1 else 0 end as redline_complete
from ar_bill_detail_fee fee
join ar_bill_detail d on d.detail_id = fee.detail_id
join ar_bill b on b.ar_bill_id = d.ar_bill_id
<include refid="billConditions"/>
group by fee.detail_id
) f on f.detail_id = d.detail_id
<include refid="billConditions"/>
group by d.ar_bill_id
) a on a.ar_bill_id = b.ar_bill_id
<include refid="billConditions"/>
</sql>
<select id="selectBills" resultMap="row">
<include refid="billRows"/>
order by b.bill_date desc, b.ar_bill_id desc
</select>
<select id="selectSummary" resultMap="summary">
select t.currency, count(*) as bill_count,
sum(t.sales_amount) as sales_amount, sum(t.product_amount) as product_amount,
sum(t.sales_gross_profit) as sales_gross_profit,
case when sum(case when t.profit_incomplete = 0 then t.sales_amount else null end) = 0 then null
else round(sum(t.sales_gross_profit) * 100 /
sum(case when t.profit_incomplete = 0 then t.sales_amount else null end), 4) end as sales_gross_margin_rate,
sum(t.written_off_amount) as written_off_amount, sum(t.unwritten_amount) as unwritten_amount,
max(commission.commission_amount) as commission_amount
from (<include refid="billRows"/>) t
left join (
select b.currency, sum(r.commission_amount) as commission_amount
from ar_bill b join ar_profit_commission_result r
on r.ar_bill_id = b.ar_bill_id and r.currency = b.currency and r.result_status = 'READY'
<include refid="billConditions"/>
and b.status = 'WRITTEN_OFF'
group by b.currency
) commission on commission.currency = t.currency
group by t.currency order by t.currency
</select>
<select id="selectSalesOptions" resultType="com.bms.receivable.profit.ArProfitSalesOption">
select u.user_id as userId, u.nick_name as name, u.user_name as code
from sys_user u
where u.del_flag = '0' and u.status = '0'
<if test="keyword != null and keyword != ''">
and (u.nick_name like concat('%', #{keyword}, '%')
or u.user_name like concat('%', #{keyword}, '%'))
</if>
order by u.nick_name, u.user_id
limit 50
</select>
<select id="selectBillDetails" resultMap="detail">
select d.detail_id, d.order_no, d.product_name, d.currency, d.total_amount
from ar_bill_detail d join ar_bill b on b.ar_bill_id = d.ar_bill_id
where b.ar_bill_id = #{query.arBillId}
and b.status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF') and b.generation_status = 'READY'
<include refid="scopeCondition"/>
order by d.detail_no, d.detail_id
</select>
<select id="selectFees" resultMap="fee">
select f.* from ar_bill_detail_fee f
join ar_bill_detail d on d.detail_id = f.detail_id
join ar_bill b on b.ar_bill_id = d.ar_bill_id
where d.detail_id = #{query.detailId}
and b.status in ('CONFIRMED', 'PARTIAL_WRITTEN_OFF', 'WRITTEN_OFF') and b.generation_status = 'READY'
<include refid="scopeCondition"/>
order by f.fee_no, f.detail_fee_id
</select>
</mapper>