134 lines
5.3 KiB
PHP
134 lines
5.3 KiB
PHP
<?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;
|
||
}
|
||
}
|