WaterPurchaseReceipt.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. <?php
  2. declare(strict_types=1);
  3. namespace plugin\saiadmin\app\service;
  4. use plugin\saiadmin\app\model\water\WaterAccount;
  5. use plugin\saiadmin\app\model\water\WaterEnterprise;
  6. use plugin\saiadmin\app\model\water\WaterLedger;
  7. use plugin\saiadmin\app\model\water\WaterModel;
  8. use plugin\saiadmin\app\model\water\WaterOrder;
  9. use plugin\saiadmin\app\model\water\WaterSku;
  10. use plugin\saiadmin\app\service\agent\WaterCommissionAccrual;
  11. use plugin\saiadmin\exception\ApiException;
  12. /** Only server-side catalog data or a persisted checkout snapshot may reach this service. */
  13. final class WaterPurchaseReceipt
  14. {
  15. public function issue(int $enterpriseId, array $package, string $reference, int $actor, bool $balance = false, ?int $checkoutId = null): array
  16. {
  17. return WaterModel::transaction(function () use ($enterpriseId, $package, $reference, $actor, $balance, $checkoutId) {
  18. $sku = WaterSku::query()->where('id', $package['sku_id'])->lockForUpdate()->first();
  19. $enterprise = WaterEnterprise::query()->where('id', $enterpriseId)->lockForUpdate()->first();
  20. if (!$sku || !$enterprise || (int) $sku->status !== 1 || (int) $enterprise->status !== 1) {
  21. throw new ApiException('企业或商品规格已停用或不存在');
  22. }
  23. $values = [
  24. 'enterprise_id' => $enterpriseId,
  25. 'package_id' => (int) $package['id'],
  26. 'sku_id' => (int) $package['sku_id'],
  27. 'buckets' => (int) $package['buckets'],
  28. 'amount_cents' => (int) $package['price_cents'],
  29. 'package_name' => $package['name'],
  30. ];
  31. $existing = WaterOrder::query()->where('reference', $reference)->first();
  32. if ($existing) {
  33. foreach ($values as $field => $value) {
  34. if ((string) $existing->$field !== (string) $value) {
  35. throw new ApiException('该收款凭据已被其他订单使用');
  36. }
  37. }
  38. return ['id' => (int) $existing->id, 'replayed' => true];
  39. }
  40. $now = date('Y-m-d H:i:s');
  41. $account = WaterAccount::query()->where(['enterprise_id' => $enterpriseId, 'sku_id' => $sku->id])->lockForUpdate()->first();
  42. if (!$account) {
  43. $account = WaterAccount::query()->create(['enterprise_id' => $enterpriseId, 'sku_id' => $sku->id, 'updated_at' => $now]);
  44. $account->refresh();
  45. }
  46. $order = WaterOrder::query()->create($values + ['reference' => $reference, 'created_by' => $actor, 'created_at' => $now]);
  47. $account->entitlement = (int) $account->entitlement + $values['buckets'];
  48. $account->updated_at = $now;
  49. $account->save();
  50. WaterLedger::query()->create([
  51. 'kind' => 'purchase', 'created_by' => $actor, 'sku_id' => $sku->id,
  52. 'enterprise_id' => $enterpriseId, 'quantity' => $values['buckets'],
  53. 'amount_cents' => $values['amount_cents'], 'reference' => $reference,
  54. 'note' => $balance ? '企业余额支付,按订单快照登记套餐权益' : '已核实线下收款,登记套餐权益',
  55. 'created_at' => $now,
  56. ]);
  57. (new WaterCommissionAccrual())->record($order, $enterprise);
  58. (new \plugin\saiadmin\app\service\promotion\PromotionReferrals())->purchased($order, $checkoutId);
  59. return ['id' => (int) $order->id];
  60. });
  61. }
  62. }