feat(accounting): document colleague trades on configured accounts
Post Montzar-covered buy/sell to Zarin/Tahesab/Pargar using montzar_account_* settings, and harden public storage URL/MIME handling for uploads. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Http\Controllers\Admin\TahesabController;
|
||||
use App\Http\Controllers\Admin\ZarinController;
|
||||
use App\Models\Order;
|
||||
use App\Models\PargarSyncLog;
|
||||
use App\Models\Tahesab;
|
||||
use App\Models\Zarin;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* سند حسابداری سمت همکار (Montzar) — جدا از سند مشتری.
|
||||
* کد حساب از settings: montzar_account_{zarin|tahesab|pargar}
|
||||
*/
|
||||
class ColleagueAccountingService
|
||||
{
|
||||
public function __construct(
|
||||
private ConfigService $config,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* بعد از پوشش سفارش روی همکار، سند را روی کد حساب همکار ثبت/صف میکند.
|
||||
*
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public function recordCoveredTrade(array $data): void
|
||||
{
|
||||
if (! $this->config->usesMontzarPricing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$order = $data['order'] ?? null;
|
||||
if (! $order instanceof Order || ! $order->id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $this->orderCoveredByColleague($order, $data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$provider = $this->config->accountingProvider();
|
||||
$accountCode = $this->colleagueAccountCode($provider);
|
||||
if ($accountCode === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->alreadyQueued($order, $provider)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = $this->buildColleaguePayload($data, $order, $accountCode);
|
||||
|
||||
try {
|
||||
match ($provider) {
|
||||
ConfigService::ACCOUNTING_ZARIN => app(ZarinController::class)->storeTrade($payload),
|
||||
ConfigService::ACCOUNTING_TAHESAB => app(TahesabController::class)->storeTrade($payload),
|
||||
ConfigService::ACCOUNTING_PARGAR => $this->queuePargarColleagueTrade($order, $payload, $accountCode),
|
||||
default => null,
|
||||
};
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
public function colleagueAccountCode(string $provider): ?string
|
||||
{
|
||||
$key = match ($provider) {
|
||||
ConfigService::ACCOUNTING_ZARIN => 'montzar_account_zarin',
|
||||
ConfigService::ACCOUNTING_TAHESAB => 'montzar_account_tahesab',
|
||||
ConfigService::ACCOUNTING_PARGAR => 'montzar_account_pargar',
|
||||
default => null,
|
||||
};
|
||||
if ($key === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$code = trim($this->config->getString($key, ''));
|
||||
if ($code === '' || in_array($code, ['0', '-1'], true)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
private function orderCoveredByColleague(Order $order, array $data): bool
|
||||
{
|
||||
if (Schema::hasColumn('orders', 'provider_id') && ! empty($order->provider_id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (! empty($data['provider_id'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return Schema::hasColumn('orders', 'total_price_montzar')
|
||||
&& $order->total_price_montzar !== null
|
||||
&& (float) $order->total_price_montzar > 0;
|
||||
}
|
||||
|
||||
private function alreadyQueued(Order $order, string $provider): bool
|
||||
{
|
||||
return match ($provider) {
|
||||
ConfigService::ACCOUNTING_ZARIN => Zarin::query()
|
||||
->where('order_id', $order->id)
|
||||
->where('desc', 'like', '%همکار%')
|
||||
->exists(),
|
||||
ConfigService::ACCOUNTING_TAHESAB => Tahesab::query()
|
||||
->where('order_id', $order->id)
|
||||
->where('desc', 'like', '%همکار%')
|
||||
->exists(),
|
||||
ConfigService::ACCOUNTING_PARGAR => PargarSyncLog::query()
|
||||
->where('order_id', $order->id)
|
||||
->where('data', 'like', '%"colleague_leg":true%')
|
||||
->exists(),
|
||||
default => true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function buildColleaguePayload(array $data, Order $order, string $accountCode): array
|
||||
{
|
||||
$amount = abs((float) ($order->amount ?? $data['amount'] ?? 0));
|
||||
$montzarUnit = Schema::hasColumn('orders', 'total_price_montzar')
|
||||
? (float) ($order->total_price_montzar ?? 0)
|
||||
: 0.0;
|
||||
$price = $montzarUnit > 0
|
||||
? $montzarUnit
|
||||
: (float) ($order->price ?? $data['price'] ?? 0);
|
||||
$total = $amount * $price;
|
||||
$direction = (int) ($order->direction ?? $data['direction'] ?? 0);
|
||||
$action = $direction === 1 ? 'خرید' : 'فروش';
|
||||
$sharh = "{$action} از اپلیکیشن همکار";
|
||||
|
||||
$payload = $data;
|
||||
$payload['order'] = $order;
|
||||
$payload['customer_id'] = (int) ($order->customer_id ?? $data['customer_id'] ?? 0);
|
||||
$payload['amount'] = $amount;
|
||||
$payload['price'] = $price;
|
||||
$payload['total_price'] = $total;
|
||||
$payload['direction'] = $direction;
|
||||
$payload['product_id'] = $order->product_id ?? ($data['product_id'] ?? null);
|
||||
$payload['accounting_account_code'] = $accountCode;
|
||||
$payload['colleague_leg'] = true;
|
||||
$payload['sharh_override'] = $sharh;
|
||||
$payload['pay_at'] = $order->pay_at ?? $order->created_at ?? ($data['pay_at'] ?? now());
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $payload
|
||||
*/
|
||||
private function queuePargarColleagueTrade(Order $order, array $payload, string $accountCode): void
|
||||
{
|
||||
if (! $this->config->isPargarAccounting()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$direction = (int) ($payload['direction'] ?? 0);
|
||||
$desc = (string) ($payload['sharh_override'] ?? 'معامله با اپلیکیشن همکار');
|
||||
|
||||
PargarSyncLog::create([
|
||||
'customer_id' => $order->customer_id,
|
||||
'amount' => $payload['amount'] ?? $order->amount,
|
||||
'desc' => $desc,
|
||||
'order_id' => $order->id,
|
||||
'date' => $order->pay_at ?? $order->created_at,
|
||||
'type' => PargarSyncService::TYPE_ORDER,
|
||||
'sync_status' => PargarSyncService::STATUS_PENDING,
|
||||
'data' => json_encode([
|
||||
'handler' => 'exportColleagueOrder',
|
||||
'colleague_leg' => true,
|
||||
'colleague_account_id' => $accountCode,
|
||||
'direction' => $direction,
|
||||
'price' => $payload['price'] ?? $order->price,
|
||||
'total_price' => $payload['total_price'] ?? $order->total_price,
|
||||
'payment_kind' => PargarSyncService::PAYMENT_CASH,
|
||||
'product_id' => $order->product_id,
|
||||
'from_cart' => false,
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user