Catalog.php 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <?php
  2. declare(strict_types=1);
  3. namespace app\miniapi\service;
  4. use app\miniapi\http\Fields;
  5. use app\miniapi\http\Pagination;
  6. use app\miniapi\exception\ApiException;
  7. use plugin\saiadmin\app\model\water\WaterPackage;
  8. use plugin\saiadmin\app\model\water\WaterSku;
  9. final class Catalog
  10. {
  11. public function query()
  12. {
  13. return WaterPackage::query()->with('sku')->where('status', 1)->whereIn('sku_id', WaterSku::query()->where('status', 1)->select('id'));
  14. }
  15. public function present($package): array
  16. {
  17. $sku = $package->sku;
  18. return [
  19. 'id' => (int) $package->id,
  20. 'name' => $package->name,
  21. 'sku_id' => (int) $package->sku_id,
  22. 'sku_name' => $sku?->name,
  23. 'liters' => $sku ? (float) $sku->liters : null,
  24. 'buckets' => (int) $package->buckets,
  25. 'price_cents' => (int) $package->price_cents,
  26. 'unit_price_cents' => (int) round($package->price_cents / max(1, $package->buckets)),
  27. 'category' => null,
  28. 'valid_months' => null,
  29. 'includes_device' => null,
  30. ];
  31. }
  32. public function listing(array $input): array
  33. {
  34. $page = new Pagination($input);
  35. $query = $this->query();
  36. $keyword = Fields::text($input, 'keyword', 120, false);
  37. Fields::choice($input, 'category', ['all'], 'all');
  38. if ($keyword !== '') {
  39. $query->where('name', 'like', '%' . $keyword . '%');
  40. }
  41. $total = (clone $query)->count();
  42. return $page->result($query->orderByDesc('id')->offset($page->offset())->limit($page->pageSize)->get()->map($this->present(...))->all(), $total)
  43. + [
  44. 'categories' => [[
  45. 'value' => 'all',
  46. 'label' => '全部',
  47. ]],
  48. 'capabilities' => ['category_filter' => false],
  49. ];
  50. }
  51. public function detail(int $id): array
  52. {
  53. $package = $this->query()->find($id);
  54. if (!$package) {
  55. throw new ApiException(40401, '套餐不存在或已下架', 404);
  56. }
  57. return $this->present($package);
  58. }
  59. /** Lock the complete set before SKU rows, so creating a checkout has one coherent snapshot. */
  60. public function lockedDetails(array $ids): array
  61. {
  62. $packages = WaterPackage::query()->whereIn('id', $ids)->orderBy('id')->lockForUpdate()->get();
  63. $skus = WaterSku::query()->whereIn('id', $packages->pluck('sku_id')->unique()->all())
  64. ->orderBy('id')->lockForUpdate()->get()->keyBy('id');
  65. $result = [];
  66. foreach ($packages as $package) {
  67. $sku = $skus->get($package->sku_id);
  68. if ((int) $package->status !== 1 || !$sku || (int) $sku->status !== 1) {
  69. throw new ApiException(40401, '套餐不存在或已下架', 404);
  70. }
  71. $package->setRelation('sku', $sku);
  72. $result[(int) $package->id] = $this->present($package);
  73. }
  74. if (count($result) !== count($ids)) {
  75. throw new ApiException(40401, '套餐不存在或已下架', 404);
  76. }
  77. return $result;
  78. }
  79. }