CaiWuXiTong/modules/EcommerceFinance/Services/SupplierReturnAccounting.php

134 lines
5.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Modules\EcommerceFinance\Services;
/**
* 退货记账归属:同一笔退货数据同时供财务端和厂家端展示。
*
* 备注中出现“记账物流”时,表示该部分不扣厂家、转物流记账;
* 当前终版数据由业务先调整厂家净数量/金额,备注保留原始数量及转运数量。
*/
class SupplierReturnAccounting
{
/** @param array<string,mixed> $row */
public function enrich(array $row): array
{
$remark = trim((string) ($row['remark'] ?? ''));
$title = trim((string) ($row['title'] ?? ''));
$isLogistics = preg_match('/记账物流|物流记账|物流.*不记账|不记账.*物流/u', $remark) === 1;
$isNoBookkeeping = ! $isLogistics && str_contains($remark, '不记账');
$target = $isLogistics ? '物流' : ($isNoBookkeeping ? '不记账' : '厂家');
$logisticsQty = 0.0;
$originalQty = 0.0;
if ($isLogistics) {
if (preg_match('/\*\s*(\d+(?:\.\d+)?)\s*记账物流/u', $remark, $matches) === 1
|| preg_match('/记账物流\s*[×xX*]?\s*(\d+(?:\.\d+)?)/u', $remark, $matches) === 1) {
$logisticsQty = (float) $matches[1];
}
if (preg_match('/原数量\s*(\d+(?:\.\d+)?)/u', $remark, $matches) === 1) {
$originalQty = (float) $matches[1];
}
if ($logisticsQty === 0.0 && $originalQty > 0) {
$logisticsQty = max(0.0, $originalQty - $this->number($row['qty'] ?? 0));
}
}
$qty = $this->number($row['qty'] ?? 0);
$unitPrice = $this->number($row['unit_price'] ?? $row['guess_unit_price'] ?? 0);
$amount = $this->number($row['amount'] ?? $row['guess_amount'] ?? 0);
if ($amount === 0.0 && $qty !== 0.0) {
$amount = $qty * $unitPrice;
}
if ($unitPrice === 0.0 && $qty !== 0.0) {
$unitPrice = $amount / $qty;
}
$supplierQty = $qty;
$supplierAmount = $amount;
$amountContainsLogistics = $originalQty > 0
&& $logisticsQty > 0
&& abs($amount - ($originalQty * $unitPrice)) < 0.01;
if ($amountContainsLogistics) {
$supplierQty = max(0.0, $originalQty - $logisticsQty);
$supplierAmount = max(0.0, $amount - ($logisticsQty * $unitPrice));
}
$row['_accounting_target'] = $target;
$row['_accounting_label'] = $isLogistics ? '转物流记账' : ($isNoBookkeeping ? '不记账' : '厂家扣减');
$row['_accounting_note'] = $isLogistics
? '不扣本厂家,转' . ($title !== '' ? $title : '物流') . '记账'
: ($isNoBookkeeping ? '本厂家不记账' : '按厂家退货扣减');
$row['_logistics_qty'] = $isLogistics ? $logisticsQty : 0.0;
$row['_logistics_amount'] = $isLogistics
? round($logisticsQty * $unitPrice, 2)
: 0.0;
$row['_logistics_company'] = $isLogistics ? $title : '';
$row['_supplier_qty'] = round($supplierQty, 2);
$row['_supplier_amount'] = round($supplierAmount, 2);
return $row;
}
/**
* @param list<array<string,mixed>> $rows
* @return array{count:int,supplier_rows:int,supplier_qty:float,supplier_amount:float,logistics_rows:int,logistics_qty:float,logistics_amount:float,logistics_companies:list<string>,no_bookkeeping_rows:int}
*/
public function summarize(array $rows): array
{
$summary = [
'count' => count($rows),
'supplier_rows' => 0,
'supplier_qty' => 0.0,
'supplier_amount' => 0.0,
'logistics_rows' => 0,
'logistics_qty' => 0.0,
'logistics_amount' => 0.0,
'logistics_companies' => [],
'no_bookkeeping_rows' => 0,
];
$companies = [];
foreach ($rows as $row) {
$row = $this->enrich($row);
$target = (string) $row['_accounting_target'];
if ($target === '不记账') {
$summary['no_bookkeeping_rows']++;
continue;
}
$summary['supplier_rows']++;
$summary['supplier_qty'] += (float) $row['_supplier_qty'];
$summary['supplier_amount'] += (float) $row['_supplier_amount'];
if ($target !== '物流') {
continue;
}
$summary['logistics_rows']++;
$summary['logistics_qty'] += (float) $row['_logistics_qty'];
$summary['logistics_amount'] += (float) $row['_logistics_amount'];
$company = trim((string) $row['_logistics_company']);
if ($company !== '') {
$companies[$company] = true;
}
}
$summary['supplier_qty'] = round($summary['supplier_qty'], 2);
$summary['supplier_amount'] = round($summary['supplier_amount'], 2);
$summary['logistics_qty'] = round($summary['logistics_qty'], 2);
$summary['logistics_amount'] = round($summary['logistics_amount'], 2);
$summary['logistics_companies'] = array_keys($companies);
return $summary;
}
private function number(mixed $value): float
{
$raw = trim((string) $value);
return is_numeric(str_replace(',', '', $raw)) ? (float) str_replace(',', '', $raw) : 0.0;
}
}