added rahimi dashboard
This commit is contained in:
@@ -773,7 +773,7 @@ class DashboardController extends Controller
|
|||||||
report($e);
|
report($e);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'message' => 'خواندن دفتر همکار ناموفق بود: ' . $e->getMessage(),
|
'message' => 'محاسبه پوشش همکار ناموفق بود: ' . $e->getMessage(),
|
||||||
], 422);
|
], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ use Hekmatinasser\Verta\Verta;
|
|||||||
use Illuminate\Support\Facades\Schema;
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* تطبیق دفتر اکانت روی نود همکار (Montzar) با سفارشهای مچشدهٔ اپ.
|
* حساب پوشش همکار برای خرید/فروش آبشدهٔ کیف اصلی — اول از روی سفارشهای اپ،
|
||||||
|
* و در صورت دسترسی، مقایسهٔ اختیاری با دفتر زندهٔ نود Montzar.
|
||||||
* ربطی به تهحساب / زرین / پرگار ندارد.
|
* ربطی به تهحساب / زرین / پرگار ندارد.
|
||||||
*/
|
*/
|
||||||
class MontzarReconcileService
|
class MontzarReconcileService
|
||||||
@@ -31,118 +32,166 @@ class MontzarReconcileService
|
|||||||
$start = Carbon::parse($startDate)->startOfDay();
|
$start = Carbon::parse($startDate)->startOfDay();
|
||||||
$end = Carbon::parse($endDate)->endOfDay();
|
$end = Carbon::parse($endDate)->endOfDay();
|
||||||
|
|
||||||
$mandehRaw = $this->montzar->fetchColleagueLedgerMandeh();
|
$localOrders = $this->loadMainWalletMeltedOrders($start, $end);
|
||||||
$mandeh = $this->normalizeMandeh($mandehRaw);
|
|
||||||
|
|
||||||
$colleagueRows = $this->montzar->fetchColleagueLedgerTable(
|
|
||||||
$start->toDateString(),
|
|
||||||
$end->toDateString()
|
|
||||||
);
|
|
||||||
|
|
||||||
$classified = [];
|
|
||||||
foreach ($colleagueRows as $index => $row) {
|
|
||||||
if (!is_array($row)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$classified[] = $this->classifyColleagueRow($row, $index);
|
|
||||||
}
|
|
||||||
|
|
||||||
$localOrders = $this->loadMatchedLocalOrders($start, $end);
|
|
||||||
$localGifts = $this->loadLocalGifts($start, $end);
|
$localGifts = $this->loadLocalGifts($start, $end);
|
||||||
|
|
||||||
[$matchedPairs, $diffs, $usedOrderIds, $usedGiftIds] = $this->matchSiteRows(
|
$covered = [];
|
||||||
$classified,
|
$uncovered = [];
|
||||||
$localOrders,
|
foreach ($localOrders as $order) {
|
||||||
$localGifts
|
if (!empty($order['covered'])) {
|
||||||
);
|
$covered[] = $order;
|
||||||
|
} else {
|
||||||
foreach ($classified as $row) {
|
$uncovered[] = $order;
|
||||||
if (($row['kind'] ?? '') === 'site_buy' || ($row['kind'] ?? '') === 'site_sell') {
|
|
||||||
if (!empty($row['_matched'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$diffs[] = [
|
|
||||||
'code' => 'colleague_site_only',
|
|
||||||
'reason' => 'سند «از سایت» روی دفتر همکار هست ولی سفارش مچشدهٔ متناظر در اپ پیدا نشد.',
|
|
||||||
'colleague' => $this->publicColleagueRow($row),
|
|
||||||
'local' => null,
|
|
||||||
];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($row['_matched'])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($row['kind'], ['settlement', 'physical', 'gift', 'other'], true)) {
|
|
||||||
$diffs[] = [
|
|
||||||
'code' => $this->diffCodeForKind($row['kind']),
|
|
||||||
'reason' => $this->reasonForKind($row['kind'], $row['desc'] ?? ''),
|
|
||||||
'colleague' => $this->publicColleagueRow($row),
|
|
||||||
'local' => null,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($localOrders as $order) {
|
$localAll = $this->sumLocalOrders($localOrders, 'cash');
|
||||||
if (isset($usedOrderIds[(int) $order['id']])) {
|
$localCovered = $this->sumLocalOrders($covered, 'montzar_cash');
|
||||||
continue;
|
$localUncovered = $this->sumLocalOrders($uncovered, 'cash');
|
||||||
}
|
|
||||||
|
$diffs = [];
|
||||||
|
foreach ($uncovered as $order) {
|
||||||
$diffs[] = [
|
$diffs[] = [
|
||||||
'code' => 'local_order_only',
|
'code' => 'local_uncovered',
|
||||||
'reason' => 'سفارش مچشده در اپ هست ولی در ریز دفتر همکار (بازه) پیدا نشد.',
|
'reason' => 'خرید/فروش آبشده کیف اصلی در اپ هست ولی به همکار مچ نشده (بدون provider_id / مبلغ منتظر).',
|
||||||
'colleague' => null,
|
'colleague' => null,
|
||||||
'local' => $order,
|
'local' => $order,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($localGifts as $gift) {
|
$mandeh = null;
|
||||||
if (isset($usedGiftIds[(int) $gift['id']])) {
|
$classified = [];
|
||||||
continue;
|
$matchedPairs = [];
|
||||||
}
|
$colleagueError = null;
|
||||||
$diffs[] = [
|
$colleagueSite = $this->emptySiteSum();
|
||||||
'code' => 'gift_cover',
|
|
||||||
'reason' => 'پاداش در اپ ثبت شده؛ سند متناظر پوشش روی دفتر همکار در بازه جور نشد (یا خرید پوشش خاموش بوده).',
|
|
||||||
'colleague' => null,
|
|
||||||
'local' => $gift,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$colleagueSite = $this->sumColleagueSite($classified);
|
|
||||||
$localSite = $this->sumLocalOrders($localOrders);
|
|
||||||
|
|
||||||
$lastRemain = null;
|
$lastRemain = null;
|
||||||
if ($classified !== []) {
|
$colleagueOther = [];
|
||||||
$last = $classified[array_key_last($classified)];
|
$diffSiteGold = 0.0;
|
||||||
$lastRemain = [
|
$diffSiteRial = 0;
|
||||||
'gold' => (float) ($last['remain_gold'] ?? 0),
|
|
||||||
'rial' => (float) ($last['remain_rial'] ?? 0),
|
try {
|
||||||
];
|
$mandehRaw = $this->montzar->fetchColleagueLedgerMandeh();
|
||||||
|
$mandeh = $this->normalizeMandeh($mandehRaw);
|
||||||
|
$colleagueRows = $this->montzar->fetchColleagueLedgerTable(
|
||||||
|
$start->toDateString(),
|
||||||
|
$end->toDateString()
|
||||||
|
);
|
||||||
|
foreach ($colleagueRows as $index => $row) {
|
||||||
|
if (!is_array($row)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$classified[] = $this->classifyColleagueRow($row, $index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[$matchedPairs, , $usedOrderIds, $usedGiftIds] = $this->matchSiteRows(
|
||||||
|
$classified,
|
||||||
|
$covered,
|
||||||
|
$localGifts
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($classified as $row) {
|
||||||
|
if (($row['kind'] ?? '') === 'site_buy' || ($row['kind'] ?? '') === 'site_sell') {
|
||||||
|
if (!empty($row['_matched'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$diffs[] = [
|
||||||
|
'code' => 'colleague_site_only',
|
||||||
|
'reason' => 'سند «از سایت» روی دفتر همکار هست ولی سفارش پوشششدهٔ متناظر در اپ پیدا نشد.',
|
||||||
|
'colleague' => $this->publicColleagueRow($row),
|
||||||
|
'local' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($covered as $order) {
|
||||||
|
if (isset($usedOrderIds[(int) $order['id']])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$diffs[] = [
|
||||||
|
'code' => 'local_covered_not_in_ledger',
|
||||||
|
'reason' => 'سفارش در اپ پوشش همکار دارد ولی در ریز دفتر همکار (بازه) پیدا نشد.',
|
||||||
|
'colleague' => null,
|
||||||
|
'local' => $order,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($localGifts as $gift) {
|
||||||
|
if (isset($usedGiftIds[(int) $gift['id']])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$diffs[] = [
|
||||||
|
'code' => 'gift_uncovered',
|
||||||
|
'reason' => 'پاداش در اپ ثبت شده؛ سند پوشش روی دفتر همکار در بازه جور نشد.',
|
||||||
|
'colleague' => null,
|
||||||
|
'local' => $gift,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($classified as $row) {
|
||||||
|
if (!empty($row['_matched'])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (in_array($row['kind'], ['settlement', 'physical', 'gift', 'other'], true)) {
|
||||||
|
$colleagueOther[] = [
|
||||||
|
'code' => $this->diffCodeForKind($row['kind']),
|
||||||
|
'reason' => $this->reasonForKind($row['kind'], $row['desc'] ?? ''),
|
||||||
|
'colleague' => $this->publicColleagueRow($row),
|
||||||
|
'local' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$colleagueSite = $this->sumColleagueSite($classified);
|
||||||
|
if ($classified !== []) {
|
||||||
|
$last = $classified[array_key_last($classified)];
|
||||||
|
$lastRemain = [
|
||||||
|
'gold' => (float) ($last['remain_gold'] ?? 0),
|
||||||
|
'rial' => (float) ($last['remain_rial'] ?? 0),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// مقایسهٔ ریال فقط با مبلغ منتظر (نه قیمت مشتری با اسپرد/کارمزد)
|
||||||
|
$diffSiteGold = round(
|
||||||
|
($colleagueSite['net_gold'] ?? 0) - ($localCovered['net_gold'] ?? 0),
|
||||||
|
3
|
||||||
|
);
|
||||||
|
$diffSiteRial = (int) round(
|
||||||
|
($colleagueSite['net_rial'] ?? 0) - ($localCovered['net_rial'] ?? 0)
|
||||||
|
);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
report($e);
|
||||||
|
$colleagueError = $e->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'mandeh' => $mandeh,
|
'mandeh' => $mandeh,
|
||||||
|
'colleague_available' => $mandeh !== null && $colleagueError === null,
|
||||||
|
'colleague_error' => $colleagueError,
|
||||||
'last_table_remain' => $lastRemain,
|
'last_table_remain' => $lastRemain,
|
||||||
'summary' => [
|
'summary' => [
|
||||||
|
'local_all' => $localAll,
|
||||||
|
'local_covered' => $localCovered,
|
||||||
|
'local_uncovered' => $localUncovered,
|
||||||
|
'local_matched' => $localCovered,
|
||||||
'colleague_site' => $colleagueSite,
|
'colleague_site' => $colleagueSite,
|
||||||
'local_matched' => $localSite,
|
'diff_site_gold' => $diffSiteGold,
|
||||||
'diff_site_gold' => round(
|
'diff_site_rial' => $diffSiteRial,
|
||||||
($colleagueSite['net_gold'] ?? 0) - ($localSite['net_gold'] ?? 0),
|
'order_count' => count($localOrders),
|
||||||
3
|
'covered_count' => count($covered),
|
||||||
),
|
'uncovered_count' => count($uncovered),
|
||||||
'diff_site_rial' => (int) round(
|
|
||||||
($colleagueSite['net_rial'] ?? 0) - ($localSite['net_rial'] ?? 0)
|
|
||||||
),
|
|
||||||
'matched_count' => count($matchedPairs),
|
'matched_count' => count($matchedPairs),
|
||||||
'diff_count' => count($diffs),
|
'diff_count' => count($diffs),
|
||||||
|
'gift_count' => count($localGifts),
|
||||||
'colleague_row_count' => count($classified),
|
'colleague_row_count' => count($classified),
|
||||||
'local_order_count' => count($localOrders),
|
'local_order_count' => count($localOrders),
|
||||||
],
|
],
|
||||||
'colleague_rows' => array_map(fn ($r) => $this->publicColleagueRow($r), $classified),
|
'colleague_rows' => array_map(fn ($r) => $this->publicColleagueRow($r), $classified),
|
||||||
'local_orders' => array_values($localOrders),
|
'local_orders' => array_values($localOrders),
|
||||||
|
'local_uncovered_orders' => array_values($uncovered),
|
||||||
'local_gifts' => array_values($localGifts),
|
'local_gifts' => array_values($localGifts),
|
||||||
'matched' => $matchedPairs,
|
'matched' => $matchedPairs,
|
||||||
'diffs' => $diffs,
|
'diffs' => $diffs,
|
||||||
|
'colleague_other' => $colleagueOther,
|
||||||
'range' => [
|
'range' => [
|
||||||
'start' => $start->toDateTimeString(),
|
'start' => $start->toDateTimeString(),
|
||||||
'end' => $end->toDateTimeString(),
|
'end' => $end->toDateTimeString(),
|
||||||
@@ -150,9 +199,82 @@ class MontzarReconcileService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* خرید/فروش موفق آبشده روی کیف اصلی (main_wallet_products / main_product).
|
||||||
|
*
|
||||||
|
* @return list<array<string, mixed>>
|
||||||
|
*/
|
||||||
|
private function loadMainWalletMeltedOrders(Carbon $start, Carbon $end): array
|
||||||
|
{
|
||||||
|
$productIds = $this->mainMeltedProductIds();
|
||||||
|
|
||||||
|
$query = Order::query()
|
||||||
|
->with(['customer:id,name,mobile', 'product:id,title,group_type'])
|
||||||
|
->where('sts', 2)
|
||||||
|
->whereBetween('created_at', [$start, $end])
|
||||||
|
->orderBy('id');
|
||||||
|
|
||||||
|
if (Schema::hasColumn('orders', 'product_id')) {
|
||||||
|
$query->where(function ($q) use ($productIds) {
|
||||||
|
if ($productIds !== []) {
|
||||||
|
$q->whereIn('product_id', $productIds);
|
||||||
|
}
|
||||||
|
$q->orWhereNull('product_id');
|
||||||
|
$q->orWhereHas('product', function ($pq) {
|
||||||
|
$pq->where('group_type', 'آبشده');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$hasProvider = Schema::hasColumn('orders', 'provider_id');
|
||||||
|
$hasMontzarPrice = Schema::hasColumn('orders', 'total_price_montzar');
|
||||||
|
|
||||||
|
return $query->get()->map(function (Order $order) use ($hasProvider, $hasMontzarPrice) {
|
||||||
|
$direction = (int) $order->direction;
|
||||||
|
$amount = (float) $order->amount;
|
||||||
|
$customerCash = (float) ($order->total_price ?? $order->payment_amount ?? 0);
|
||||||
|
$montzarCash = $hasMontzarPrice ? (float) ($order->total_price_montzar ?? 0) : 0.0;
|
||||||
|
$providerId = $hasProvider ? ($order->provider_id ?? null) : null;
|
||||||
|
$covered = ($providerId !== null && $providerId !== '')
|
||||||
|
|| ($hasMontzarPrice && $order->total_price_montzar !== null);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'id' => (int) $order->id,
|
||||||
|
'type' => 'order',
|
||||||
|
'direction' => $direction,
|
||||||
|
'direction_label' => Order::$DIRECTION[$direction] ?? (string) $direction,
|
||||||
|
'amount' => round($amount, 3),
|
||||||
|
'cash' => (int) round($customerCash),
|
||||||
|
'montzar_cash' => (int) round($montzarCash),
|
||||||
|
'covered' => $covered,
|
||||||
|
'provider_id' => $providerId,
|
||||||
|
'product_id' => $order->product_id,
|
||||||
|
'product_title' => $order->product->title ?? null,
|
||||||
|
'customer_id' => (int) $order->customer_id,
|
||||||
|
'customer_name' => $order->customer->name ?? null,
|
||||||
|
'created_at' => optional($order->created_at)?->toDateTimeString(),
|
||||||
|
'date_ymd' => optional($order->created_at)?->toDateString(),
|
||||||
|
];
|
||||||
|
})->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return list<int>
|
||||||
|
*/
|
||||||
|
private function mainMeltedProductIds(): array
|
||||||
|
{
|
||||||
|
$ids = $this->config->mainWalletProductIds();
|
||||||
|
$main = $this->config->mainProductId();
|
||||||
|
if ($main) {
|
||||||
|
$ids[] = (int) $main;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values(array_unique(array_filter($ids)));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param list<array<string, mixed>> $raw
|
* @param list<array<string, mixed>> $raw
|
||||||
* @return array{gold: float, cash: float, gold_unit: string, cash_unit: string, items: list<array<string, mixed>>}
|
* @return array{gold: float, cash: float, gold_abs: float, cash_abs: float, gold_state: string, rial_state: string, gold_unit: string, cash_unit: string, items: list<array<string, mixed>>}
|
||||||
*/
|
*/
|
||||||
private function normalizeMandeh(array $raw): array
|
private function normalizeMandeh(array $raw): array
|
||||||
{
|
{
|
||||||
@@ -203,7 +325,7 @@ class MontzarReconcileService
|
|||||||
$besRial = $this->num($row['besRial'] ?? 0);
|
$besRial = $this->num($row['besRial'] ?? 0);
|
||||||
|
|
||||||
$kind = 'other';
|
$kind = 'other';
|
||||||
$siteDirection = null; // 1=فروش همکار به اپ (=خرید مشتری)، 2=خرید همکار از اپ (=فروش مشتری)
|
$siteDirection = null;
|
||||||
|
|
||||||
$fromSite = str_contains($desc, 'سايت') || str_contains($desc, 'سایت');
|
$fromSite = str_contains($desc, 'سايت') || str_contains($desc, 'سایت');
|
||||||
if ($fromSite && (str_contains($desc, 'فروش') || str_starts_with($desc, 'فروش'))) {
|
if ($fromSite && (str_contains($desc, 'فروش') || str_starts_with($desc, 'فروش'))) {
|
||||||
@@ -220,14 +342,12 @@ class MontzarReconcileService
|
|||||||
$kind = 'gift';
|
$kind = 'gift';
|
||||||
}
|
}
|
||||||
|
|
||||||
$gregorianDate = $this->colleagueDateToYmd((string) ($row['date'] ?? ''));
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'index' => $index,
|
'index' => $index,
|
||||||
'id' => $row['id'] ?? null,
|
'id' => $row['id'] ?? null,
|
||||||
'doc_id' => $row['docId'] ?? null,
|
'doc_id' => $row['docId'] ?? null,
|
||||||
'date' => $row['date'] ?? null,
|
'date' => $row['date'] ?? null,
|
||||||
'date_ymd' => $gregorianDate,
|
'date_ymd' => $this->colleagueDateToYmd((string) ($row['date'] ?? '')),
|
||||||
'desc' => $desc,
|
'desc' => $desc,
|
||||||
'kind' => $kind,
|
'kind' => $kind,
|
||||||
'site_direction' => $siteDirection,
|
'site_direction' => $siteDirection,
|
||||||
@@ -245,51 +365,6 @@ class MontzarReconcileService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return list<array<string, mixed>>
|
|
||||||
*/
|
|
||||||
private function loadMatchedLocalOrders(Carbon $start, Carbon $end): array
|
|
||||||
{
|
|
||||||
$query = Order::query()
|
|
||||||
->with(['customer:id,name,mobile'])
|
|
||||||
->where('sts', 2)
|
|
||||||
->whereBetween('created_at', [$start, $end])
|
|
||||||
->orderBy('id');
|
|
||||||
|
|
||||||
if (Schema::hasColumn('orders', 'provider_id')) {
|
|
||||||
$query->where(function ($q) {
|
|
||||||
$q->whereNotNull('provider_id');
|
|
||||||
if (Schema::hasColumn('orders', 'total_price_montzar')) {
|
|
||||||
$q->orWhereNotNull('total_price_montzar');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} elseif (Schema::hasColumn('orders', 'total_price_montzar')) {
|
|
||||||
$query->whereNotNull('total_price_montzar');
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->get()->map(function (Order $order) {
|
|
||||||
$direction = (int) $order->direction;
|
|
||||||
$amount = (float) $order->amount;
|
|
||||||
$cash = (float) ($order->total_price ?? $order->payment_amount ?? 0);
|
|
||||||
|
|
||||||
return [
|
|
||||||
'id' => (int) $order->id,
|
|
||||||
'type' => 'order',
|
|
||||||
'direction' => $direction,
|
|
||||||
'direction_label' => Order::$DIRECTION[$direction] ?? (string) $direction,
|
|
||||||
'amount' => round($amount, 3),
|
|
||||||
'cash' => (int) round($cash),
|
|
||||||
'provider_id' => $order->provider_id ?? null,
|
|
||||||
'customer_id' => (int) $order->customer_id,
|
|
||||||
'customer_name' => $order->customer->name ?? null,
|
|
||||||
'created_at' => optional($order->created_at)?->toDateTimeString(),
|
|
||||||
'date_ymd' => optional($order->created_at)?->toDateString(),
|
|
||||||
];
|
|
||||||
})->all();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return list<array<string, mixed>>
|
* @return list<array<string, mixed>>
|
||||||
*/
|
*/
|
||||||
@@ -309,6 +384,8 @@ class MontzarReconcileService
|
|||||||
'direction_label' => 'خرید پوشش پاداش',
|
'direction_label' => 'خرید پوشش پاداش',
|
||||||
'amount' => round((float) $row->gold, 3),
|
'amount' => round((float) $row->gold, 3),
|
||||||
'cash' => 0,
|
'cash' => 0,
|
||||||
|
'montzar_cash' => 0,
|
||||||
|
'covered' => false,
|
||||||
'note' => $row->note,
|
'note' => $row->note,
|
||||||
'customer_id' => (int) ($row->customer_to_id ?: $row->customer_id),
|
'customer_id' => (int) ($row->customer_to_id ?: $row->customer_id),
|
||||||
'created_at' => optional($row->created_at)?->toDateTimeString(),
|
'created_at' => optional($row->created_at)?->toDateTimeString(),
|
||||||
@@ -385,16 +462,18 @@ class MontzarReconcileService
|
|||||||
if (isset($usedOrders[(int) $order['id']])) {
|
if (isset($usedOrders[(int) $order['id']])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
$orderRial = (float) (($order['montzar_cash'] ?? 0) > 0
|
||||||
|
? $order['montzar_cash']
|
||||||
|
: $order['cash']);
|
||||||
if (
|
if (
|
||||||
$this->goldClose((float) $order['amount'], $targetGold)
|
$this->goldClose((float) $order['amount'], $targetGold)
|
||||||
&& $this->rialClose((float) $order['cash'], $targetRial)
|
&& $this->rialClose($orderRial, $targetRial)
|
||||||
) {
|
) {
|
||||||
$found = $order;
|
$found = $order;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback: فقط گرم در همان روز
|
|
||||||
if (!$found) {
|
if (!$found) {
|
||||||
foreach ($candidates as $order) {
|
foreach ($candidates as $order) {
|
||||||
if (isset($usedOrders[(int) $order['id']])) {
|
if (isset($usedOrders[(int) $order['id']])) {
|
||||||
@@ -422,13 +501,28 @@ class MontzarReconcileService
|
|||||||
return [$matchedPairs, $diffs, $usedOrders, $usedGifts];
|
return [$matchedPairs, $diffs, $usedOrders, $usedGifts];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{buy_gold: float, sell_gold: float, buy_rial: float, sell_rial: float, net_gold: float, net_rial: float}
|
||||||
|
*/
|
||||||
|
private function emptySiteSum(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'buy_gold' => 0.0,
|
||||||
|
'sell_gold' => 0.0,
|
||||||
|
'buy_rial' => 0,
|
||||||
|
'sell_rial' => 0,
|
||||||
|
'net_gold' => 0.0,
|
||||||
|
'net_rial' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param list<array<string, mixed>> $classified
|
* @param list<array<string, mixed>> $classified
|
||||||
* @return array{buy_gold: float, sell_gold: float, buy_rial: float, sell_rial: float, net_gold: float, net_rial: float}
|
* @return array{buy_gold: float, sell_gold: float, buy_rial: float, sell_rial: float, net_gold: float, net_rial: float}
|
||||||
*/
|
*/
|
||||||
private function sumColleagueSite(array $classified): array
|
private function sumColleagueSite(array $classified): array
|
||||||
{
|
{
|
||||||
$buyGold = 0.0; // فروش همکار به اپ
|
$buyGold = 0.0;
|
||||||
$sellGold = 0.0;
|
$sellGold = 0.0;
|
||||||
$buyRial = 0.0;
|
$buyRial = 0.0;
|
||||||
$sellRial = 0.0;
|
$sellRial = 0.0;
|
||||||
@@ -456,9 +550,10 @@ class MontzarReconcileService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param list<array<string, mixed>> $orders
|
* @param list<array<string, mixed>> $orders
|
||||||
|
* @param 'cash'|'montzar_cash' $rialField
|
||||||
* @return array{buy_gold: float, sell_gold: float, buy_rial: float, sell_rial: float, net_gold: float, net_rial: float}
|
* @return array{buy_gold: float, sell_gold: float, buy_rial: float, sell_rial: float, net_gold: float, net_rial: float}
|
||||||
*/
|
*/
|
||||||
private function sumLocalOrders(array $orders): array
|
private function sumLocalOrders(array $orders, string $rialField = 'cash'): array
|
||||||
{
|
{
|
||||||
$buyGold = 0.0;
|
$buyGold = 0.0;
|
||||||
$sellGold = 0.0;
|
$sellGold = 0.0;
|
||||||
@@ -466,12 +561,16 @@ class MontzarReconcileService
|
|||||||
$sellRial = 0.0;
|
$sellRial = 0.0;
|
||||||
|
|
||||||
foreach ($orders as $order) {
|
foreach ($orders as $order) {
|
||||||
|
$rial = (float) ($order[$rialField] ?? 0);
|
||||||
|
if ($rialField === 'montzar_cash' && $rial <= 0) {
|
||||||
|
$rial = (float) ($order['cash'] ?? 0);
|
||||||
|
}
|
||||||
if ((int) $order['direction'] === 1) {
|
if ((int) $order['direction'] === 1) {
|
||||||
$buyGold += (float) $order['amount'];
|
$buyGold += (float) $order['amount'];
|
||||||
$buyRial += (float) $order['cash'];
|
$buyRial += $rial;
|
||||||
} else {
|
} else {
|
||||||
$sellGold += (float) $order['amount'];
|
$sellGold += (float) $order['amount'];
|
||||||
$sellRial += (float) $order['cash'];
|
$sellRial += $rial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -509,8 +608,8 @@ class MontzarReconcileService
|
|||||||
private function reasonForKind(string $kind, string $desc): string
|
private function reasonForKind(string $kind, string $desc): string
|
||||||
{
|
{
|
||||||
return match ($kind) {
|
return match ($kind) {
|
||||||
'settlement' => 'واریز/برداشت یا تعدیل روی دفتر همکار (بدون توضیح سایت) — معمولاً تسویه بانکی است و در اپ سفارش نیست.',
|
'settlement' => 'واریز/برداشت یا تعدیل روی دفتر همکار — معمولاً تسویه است و سفارش اپ نیست.',
|
||||||
'physical' => 'پرداخت فیزیکی روی دفتر همکار — در کیف مشتری لزوماً همان لحظه کم نمیشود.',
|
'physical' => 'پرداخت فیزیکی روی دفتر همکار.',
|
||||||
'gift' => 'سند مرتبط با پاداش روی دفتر همکار.',
|
'gift' => 'سند مرتبط با پاداش روی دفتر همکار.',
|
||||||
default => $desc !== ''
|
default => $desc !== ''
|
||||||
? 'سند سایر روی دفتر همکار: ' . $desc
|
? 'سند سایر روی دفتر همکار: ' . $desc
|
||||||
@@ -525,7 +624,6 @@ class MontzarReconcileService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// جلالی شبیه 1405-05-11 (سال جلالی معمولاً ۱۳xx/۱۴xx)
|
|
||||||
if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $date, $m) && (int) $m[1] >= 1300 && (int) $m[1] < 1600) {
|
if (preg_match('/^(\d{4})-(\d{1,2})-(\d{1,2})$/', $date, $m) && (int) $m[1] >= 1300 && (int) $m[1] < 1600) {
|
||||||
try {
|
try {
|
||||||
return Verta::createJalaliDate((int) $m[1], (int) $m[2], (int) $m[3])
|
return Verta::createJalaliDate((int) $m[1], (int) $m[2], (int) $m[3])
|
||||||
|
|||||||
Reference in New Issue
Block a user