fix some bugs from accounting
This commit is contained in:
@@ -8,7 +8,7 @@ use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\Product;
|
||||
use App\Models\Zarin;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\AccountingProductDocMapper;
|
||||
use App\Services\ZarinSyncService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -1088,7 +1088,8 @@ class ZarinController extends Controller
|
||||
'id' => $order->product_id,
|
||||
'metal_id' => $existing->type === 'طلا' ? 1 : 2,
|
||||
],
|
||||
'order' => ['id' => $existing->order_id],
|
||||
'product_id' => $order->product_id ? (int) $order->product_id : null,
|
||||
'order' => ['id' => $existing->order_id, 'product_id' => $order->product_id],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1099,6 +1100,12 @@ class ZarinController extends Controller
|
||||
: false;
|
||||
}
|
||||
|
||||
$mapper = app(AccountingProductDocMapper::class);
|
||||
$product = $mapper->resolveProductFromPayload($data);
|
||||
if ($product && $mapper->shouldSkip($product)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$customer = Customer::where('id', $data['customer_id'])->first();
|
||||
|
||||
if ($customer && ($customer->moshtari_code === null)) {
|
||||
@@ -1110,9 +1117,19 @@ class ZarinController extends Controller
|
||||
return false;
|
||||
}
|
||||
|
||||
$amount = $data['amount'];
|
||||
$rawAmount = (float) $data['amount'];
|
||||
$count = $mapper->accountingQty($product, $rawAmount, $data);
|
||||
$vazn = $mapper->accountingWeight($product, $rawAmount, $data);
|
||||
$isBuy = (int) ($data['direction'] ?? 0) === 1;
|
||||
$orderId = $data['order']['id'] ?? ($existing->order_id ?? null);
|
||||
$metalId = (int) ($data['product']['metal_id'] ?? 1);
|
||||
$title = $mapper->productTitle($product);
|
||||
$action = $isBuy ? 'خرید' : 'فروش';
|
||||
$sharh = trim($title !== '' ? "{$action} {$title}" : "{$action} {$mapper->kindLabel($mapper->resolveKind($product))}");
|
||||
$syncAmount = $mapper->isCountDoc($product) ? $count : $vazn;
|
||||
$uidSource = $orderId ?? null;
|
||||
if (!empty($data['line'])) {
|
||||
$uidSource = ($orderId ?? '0') . 'L' . (int) $data['line'];
|
||||
}
|
||||
|
||||
$data['handler'] = 'storeTrade';
|
||||
if ($existing && empty($existing->data)) {
|
||||
@@ -1120,84 +1137,55 @@ class ZarinController extends Controller
|
||||
}
|
||||
$zarin = $existing ?? Zarin::create([
|
||||
'customer_id' => $customer->id,
|
||||
'desc' => $data['direction'] == 1 ? 'خرید آبشده' : 'فروش آبشده',
|
||||
'amount' => $amount,
|
||||
'desc' => $sharh,
|
||||
'amount' => $syncAmount,
|
||||
'order_id' => $orderId,
|
||||
'date' => $data['pay_at'] ?? Carbon::now(),
|
||||
'type' => $metalId == 1 ? 'طلا' : 'نقره',
|
||||
'type' => $mapper->metalLabel($product),
|
||||
'created_at' => Carbon::now(),
|
||||
'data' => json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
|
||||
]);
|
||||
|
||||
$isStore = app(ConfigService::class)->isStore();
|
||||
$productId = $this->resolveProductId($data, $existing);
|
||||
|
||||
try {
|
||||
if ($isStore && $productId) {
|
||||
$product = Product::find($productId);
|
||||
if (!$product) {
|
||||
$this->sync()->markFailed($zarin, null, 'محصول برای ثبت سند زرین پیدا نشد');
|
||||
return false;
|
||||
if ($mapper->isCountDoc($product)) {
|
||||
$fi = (float) ($data['price'] ?? 0);
|
||||
if ($count > 0) {
|
||||
if (!empty($data['total_price'])) {
|
||||
$fi = ((float) $data['total_price']) / $count;
|
||||
} elseif ($fi > 0 && abs($vazn - $count) > 0.0001) {
|
||||
$fi = $fi * ($vazn / $count);
|
||||
}
|
||||
}
|
||||
|
||||
$karResult = $this->ensureZarinKarForProduct($product);
|
||||
if (empty($karResult['ok'])) {
|
||||
$this->sync()->markFailed($zarin, $karResult, 'کد کار زرین برای محصول آماده نشد');
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = [
|
||||
'kind' => 'sabtSanadTedadi',
|
||||
'parDar' => ((int) ($data['direction'] ?? 0) === 1) ? -1 : 1,
|
||||
'idHesab' => $customer->moshtari_code,
|
||||
'idKar' => (int) $karResult['idKar'],
|
||||
'fi' => $data['price'] ?? 0,
|
||||
'tedad' => $amount,
|
||||
'sharh' => $data['direction'] == 1 ? 'خرید' : 'فروش',
|
||||
'uid' => $this->zarinUid('30', $orderId),
|
||||
];
|
||||
$result = $this->postZarinCountDoc(
|
||||
$zarin,
|
||||
$data,
|
||||
$customer,
|
||||
$product,
|
||||
$count,
|
||||
$isBuy ? -1 : 1,
|
||||
$fi,
|
||||
$sharh,
|
||||
$this->zarinUid('10', $uidSource ?? $zarin->id)
|
||||
);
|
||||
} else {
|
||||
$params = [
|
||||
'kind' => 'pooli',
|
||||
'radif' => 1,
|
||||
'korf' => ((int) ($data['direction'] ?? 0) === 1) ? 'f' : 'k',
|
||||
'poolorvazn' => 'vazn',
|
||||
'meghdar' => $amount,
|
||||
'fi' => $data['price'] ?? 0,
|
||||
'hesab' => $customer->moshtari_code,
|
||||
'sharh' => $data['direction'] == 1 ? 'خرید آبشده' : 'فروش آبشده',
|
||||
'ayar' => '750',
|
||||
'movaghat' => '',
|
||||
'idFactor' => '',
|
||||
'uid' => $this->zarinUid('10', $orderId),
|
||||
];
|
||||
}
|
||||
|
||||
$http = $this->zarinRequest($params);
|
||||
if (!$http) {
|
||||
$this->sync()->markFailed($zarin, null, 'تنظیمات زرین کامل نیست');
|
||||
return 'تنظیمات زرین کامل نیست. zarin_api یا zarin_token تنظیم نشده است.';
|
||||
}
|
||||
|
||||
[$response, $httpError] = $this->zarinDecodeResponse($http);
|
||||
if ($httpError) {
|
||||
$this->sync()->markFailed($zarin, $response ?? $httpError, $httpError);
|
||||
return false;
|
||||
$result = $this->postZarinWeightDoc(
|
||||
$zarin,
|
||||
$data,
|
||||
$customer,
|
||||
$vazn,
|
||||
$isBuy ? 'f' : 'k',
|
||||
(float) ($data['price'] ?? 0),
|
||||
$sharh,
|
||||
$mapper->jensFelez($product) ?? 0,
|
||||
$this->zarinUid('10', $uidSource ?? $zarin->id)
|
||||
);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->sync()->markFailed($zarin, $e->getMessage());
|
||||
return $e->getMessage();
|
||||
}
|
||||
|
||||
$flat = $this->extractResponseRow(is_array($response) ? $response : null);
|
||||
|
||||
if ($this->sync()->responseOk(is_array($response) ? $response : []) || $this->sync()->responseOk($flat)) {
|
||||
$this->sync()->markSuccess($zarin, is_array($response) ? $response : $flat, $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
$this->sync()->markFailed($zarin, $response, 'ثبت سند معامله در زرین ناموفق بود');
|
||||
return false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
// direction: 0 = daryaft az moshtari, 1 = pardakht be moshtari
|
||||
@@ -1413,7 +1401,7 @@ class ZarinController extends Controller
|
||||
return false;
|
||||
}
|
||||
|
||||
// direction: 1 = واریز طلا (خرید)، 0 = برداشت طلا (فروش)
|
||||
// direction: 1 = واریز، 0 = برداشت
|
||||
public function walletGold($data, ?Zarin $existing = null)
|
||||
{
|
||||
if (empty($data['customer_id']) && $existing) {
|
||||
@@ -1423,6 +1411,15 @@ class ZarinController extends Controller
|
||||
'direction' => str_contains((string) $existing->desc, 'برداشت') ? 0 : 1,
|
||||
'withdraw_id' => $existing->withdraw_id,
|
||||
]);
|
||||
$payload = json_decode((string) ($existing->data ?? ''), true);
|
||||
if (is_array($payload)) {
|
||||
if (!empty($payload['product_id'])) {
|
||||
$data['product_id'] = (int) $payload['product_id'];
|
||||
}
|
||||
if (!empty($payload['product']) && is_array($payload['product'])) {
|
||||
$data['product'] = $payload['product'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($data['customer_id'], $data['value'])) {
|
||||
@@ -1431,6 +1428,12 @@ class ZarinController extends Controller
|
||||
: false;
|
||||
}
|
||||
|
||||
$mapper = app(AccountingProductDocMapper::class);
|
||||
$product = $mapper->resolveProductFromPayload($data);
|
||||
if ($product && $mapper->shouldSkip($product)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$customer = Customer::where('id', $data['customer_id'])->first();
|
||||
|
||||
if ($customer && ($customer->moshtari_code === null)) {
|
||||
@@ -1442,16 +1445,27 @@ class ZarinController extends Controller
|
||||
return false;
|
||||
}
|
||||
|
||||
$amount = abs($data['value']);
|
||||
$rawValue = (float) $data['value'];
|
||||
$count = $mapper->accountingQty($product, $rawValue, $data);
|
||||
$vazn = $mapper->accountingWeight($product, $rawValue, $data);
|
||||
$isDeposit = (int) ($data['direction'] ?? 1) === 1;
|
||||
|
||||
$title = $mapper->productTitle($product);
|
||||
$action = $isDeposit ? 'شارژ' : 'دشارژ';
|
||||
$sharh = !empty($data['note'])
|
||||
? (string) $data['note']
|
||||
: (!empty($data['desc'])
|
||||
? (string) $data['desc']
|
||||
: trim($title !== '' ? "{$action} {$title}" : "{$action} {$mapper->kindLabel($mapper->resolveKind($product))}"));
|
||||
$data['note'] = $sharh;
|
||||
$data['handler'] = 'walletGold';
|
||||
$syncAmount = $mapper->isCountDoc($product) ? $count : $vazn;
|
||||
|
||||
$zarin = $existing ?? Zarin::create([
|
||||
'customer_id' => $customer->id,
|
||||
'desc' => $isDeposit ? 'شارژ کیف پول آبشده' : 'برداشت از کیف پول آبشده',
|
||||
'amount' => $amount,
|
||||
'desc' => $sharh,
|
||||
'amount' => $syncAmount,
|
||||
'date' => Carbon::now(),
|
||||
'type' => 'طلا',
|
||||
'type' => $mapper->metalLabel($product),
|
||||
'created_at' => Carbon::now(),
|
||||
'withdraw_id' => $data['withdraw_id'] ?? null,
|
||||
'data' => json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
|
||||
@@ -1467,50 +1481,160 @@ class ZarinController extends Controller
|
||||
$mazaneh = 1;
|
||||
}
|
||||
|
||||
$sharh = !empty($data['note'])
|
||||
? $data['note']
|
||||
: (!empty($data['desc']) ? $data['desc'] : ($isDeposit ? 'خرید آبشده' : 'فروش آبشده'));
|
||||
$data['note'] = $sharh;
|
||||
|
||||
$uidSource = $data['withdraw_id'] ?? $zarin->id;
|
||||
|
||||
try {
|
||||
$http = $this->zarinRequest([
|
||||
'kind' => 'pooli',
|
||||
'radif' => 1,
|
||||
'korf' => $isDeposit ? 'f' : 'k',
|
||||
'poolorvazn' => 'vazn',
|
||||
'meghdar' => $amount,
|
||||
'fi' => $mazaneh,
|
||||
'hesab' => $customer->moshtari_code,
|
||||
'sharh' => $sharh,
|
||||
'ayar' => '750',
|
||||
'movaghat' => '',
|
||||
'idFactor' => '',
|
||||
'uid' => $this->zarinUid('21', $uidSource),
|
||||
]);
|
||||
if ($mapper->isCountDoc($product)) {
|
||||
$unitPrice = $mazaneh;
|
||||
if ($product && (float) ($product->amount ?? 0) > 0) {
|
||||
$unitPrice = (int) round($mazaneh * (float) $product->amount);
|
||||
}
|
||||
if ($unitPrice <= 0) {
|
||||
$unitPrice = $mazaneh;
|
||||
}
|
||||
|
||||
if (!$http) {
|
||||
$this->sync()->markFailed($zarin, null, 'تنظیمات زرین کامل نیست');
|
||||
return 'تنظیمات زرین کامل نیست. zarin_api یا zarin_token تنظیم نشده است.';
|
||||
return $this->postZarinCountDoc(
|
||||
$zarin,
|
||||
$data,
|
||||
$customer,
|
||||
$product,
|
||||
$count,
|
||||
$isDeposit ? -1 : 1,
|
||||
(float) $unitPrice,
|
||||
$sharh,
|
||||
$this->zarinUid('21', $uidSource)
|
||||
);
|
||||
}
|
||||
|
||||
[$response, $httpError] = $this->zarinDecodeResponse($http);
|
||||
if ($httpError) {
|
||||
$this->sync()->markFailed($zarin, $response ?? $httpError, $httpError);
|
||||
return false;
|
||||
}
|
||||
return $this->postZarinWeightDoc(
|
||||
$zarin,
|
||||
$data,
|
||||
$customer,
|
||||
$vazn,
|
||||
$isDeposit ? 'f' : 'k',
|
||||
(float) $mazaneh,
|
||||
$sharh,
|
||||
$mapper->jensFelez($product) ?? 0,
|
||||
$this->zarinUid('21', $uidSource)
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
$this->sync()->markFailed($zarin, $e->getMessage());
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->sync()->responseOk(is_array($response) ? $response : [])) {
|
||||
$this->sync()->markSuccess($zarin, is_array($response) ? $response : [], $data);
|
||||
/**
|
||||
* سند تعدادی زرین (سکه / شمش / گوی / مکعب).
|
||||
*/
|
||||
private function postZarinCountDoc(
|
||||
Zarin $zarin,
|
||||
array $data,
|
||||
Customer $customer,
|
||||
$product,
|
||||
float $tedad,
|
||||
int $parDar,
|
||||
float $fi,
|
||||
string $sharh,
|
||||
string $uid
|
||||
) {
|
||||
if (!$product instanceof Product || empty($product->id)) {
|
||||
$this->sync()->markFailed($zarin, null, 'محصول برای سند تعدادی زرین مشخص نیست');
|
||||
return false;
|
||||
}
|
||||
|
||||
$kar = $this->ensureZarinKarForProduct($product);
|
||||
if (empty($kar['ok']) || empty($kar['idKar'])) {
|
||||
$this->sync()->markFailed($zarin, $kar ?? null, $kar['message'] ?? 'کد کار زرین برای محصول یافت نشد');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($fi <= 0) {
|
||||
$fi = 1;
|
||||
}
|
||||
|
||||
$http = $this->zarinRequest([
|
||||
'kind' => 'sabtSanadTedadi',
|
||||
'idHesab' => $customer->moshtari_code,
|
||||
'idKar' => (int) $kar['idKar'],
|
||||
'fi' => $fi,
|
||||
'tedad' => $tedad,
|
||||
'parDar' => $parDar,
|
||||
'sharh' => $sharh,
|
||||
'uid' => $uid,
|
||||
]);
|
||||
|
||||
if (!$http) {
|
||||
$this->sync()->markFailed($zarin, null, 'تنظیمات زرین کامل نیست');
|
||||
return 'تنظیمات زرین کامل نیست. zarin_api یا zarin_token تنظیم نشده است.';
|
||||
}
|
||||
|
||||
[$response, $httpError] = $this->zarinDecodeResponse($http);
|
||||
if ($httpError) {
|
||||
$this->sync()->markFailed($zarin, $response ?? $httpError, $httpError);
|
||||
return false;
|
||||
}
|
||||
|
||||
$flat = $this->extractResponseRow(is_array($response) ? $response : null);
|
||||
if ($this->sync()->responseOk(is_array($response) ? $response : []) || $this->sync()->responseOk($flat)) {
|
||||
$this->sync()->markSuccess($zarin, is_array($response) ? $response : $flat, $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
$this->sync()->markFailed($zarin, $response, 'ثبت سند طلایی کیف پول در زرین ناموفق بود');
|
||||
$this->sync()->markFailed($zarin, $response, 'ثبت سند تعدادی در زرین ناموفق بود');
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* سند وزنی زرین (آبشده طلا/نقره).
|
||||
*/
|
||||
private function postZarinWeightDoc(
|
||||
Zarin $zarin,
|
||||
array $data,
|
||||
Customer $customer,
|
||||
float $meghdar,
|
||||
string $korf,
|
||||
float $fi,
|
||||
string $sharh,
|
||||
int $jensFelez,
|
||||
string $uid
|
||||
) {
|
||||
if ($fi <= 0) {
|
||||
$fi = 1;
|
||||
}
|
||||
|
||||
$http = $this->zarinRequest([
|
||||
'kind' => 'pooli',
|
||||
'radif' => 1,
|
||||
'korf' => $korf,
|
||||
'poolorvazn' => 'vazn',
|
||||
'meghdar' => $meghdar,
|
||||
'fi' => $fi,
|
||||
'hesab' => $customer->moshtari_code,
|
||||
'sharh' => $sharh,
|
||||
'ayar' => $jensFelez === 2 ? '' : '750',
|
||||
'movaghat' => '',
|
||||
'idFactor' => '',
|
||||
'uid' => $uid,
|
||||
]);
|
||||
|
||||
if (!$http) {
|
||||
$this->sync()->markFailed($zarin, null, 'تنظیمات زرین کامل نیست');
|
||||
return 'تنظیمات زرین کامل نیست. zarin_api یا zarin_token تنظیم نشده است.';
|
||||
}
|
||||
|
||||
[$response, $httpError] = $this->zarinDecodeResponse($http);
|
||||
if ($httpError) {
|
||||
$this->sync()->markFailed($zarin, $response ?? $httpError, $httpError);
|
||||
return false;
|
||||
}
|
||||
|
||||
$flat = $this->extractResponseRow(is_array($response) ? $response : null);
|
||||
if ($this->sync()->responseOk(is_array($response) ? $response : []) || $this->sync()->responseOk($flat)) {
|
||||
$this->sync()->markSuccess($zarin, is_array($response) ? $response : $flat, $data);
|
||||
return $data;
|
||||
}
|
||||
|
||||
$this->sync()->markFailed($zarin, $response, 'ثبت سند وزنی در زرین ناموفق بود');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user