Skip to content

Commit 7ae2d84

Browse files
committed
Оформление заказа
1 parent ecfb865 commit 7ae2d84

File tree

26 files changed

+600
-103
lines changed

26 files changed

+600
-103
lines changed

.env.dist

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ EMAIL_SUBJECT_REGISTER_EN="Confirm registration"
3636
EMAIL_SUBJECT_RESET_RU="Ссылка для входа"
3737
EMAIL_SUBJECT_RESET_EN="Login link"
3838

39+
EMAIL_ADMIN=""
40+
EMAIL_SUBJECT_ORDER_NEW_ADMIN_RU="У вас новый заказ"
41+
EMAIL_SUBJECT_ORDER_NEW_ADMIN_EN="You have a new order"
42+
EMAIL_SUBJECT_ORDER_NEW_USER_RU="Вы сделали заказ"
43+
EMAIL_SUBJECT_ORDER_NEW_USER_EN="You have made an order"
44+
3945
PRODUCTS_PREFIX=products

core/db/migrations/20230824022811_user_addresses.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ static function (Blueprint $table) {
1616
$table->foreignId('user_id')
1717
->constrained('users')->cascadeOnDelete();
1818
$table->string('receiver')->nullable();
19+
$table->string('email')->nullable();
1920
$table->string('phone')->nullable();
20-
$table->tinyInteger('gender')->nullable();
2121
$table->string('company')->nullable();
2222
$table->string('address')->nullable();
2323
$table->string('country')->nullable();

core/routes.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
$group = $app->group(
77
'/api',
88
function (RouteCollectorProxy $group) {
9+
$group->get('/image/{id}', App\Controllers\Image::class);
10+
911
$group->group(
1012
'/security',
1113
static function (RouteCollectorProxy $group) {
@@ -17,8 +19,13 @@ static function (RouteCollectorProxy $group) {
1719
}
1820
);
1921

20-
$group->any('/user/profile', App\Controllers\User\Profile::class);
21-
$group->get('/image/{id}', App\Controllers\Image::class);
22+
$group->group(
23+
'/user',
24+
static function (RouteCollectorProxy $group) {
25+
$group->any('/profile', App\Controllers\User\Profile::class);
26+
$group->any('/addresses', App\Controllers\User\Addresses::class);
27+
}
28+
);
2229

2330
$group->group(
2431
'/admin',
@@ -49,7 +56,7 @@ static function (RouteCollectorProxy $group) {
4956
$group->any('/category/{category_id}/filters', App\Controllers\Web\Category\Filters::class);
5057
$group->any('/products[/{uri:.+}]', App\Controllers\Web\Products::class);
5158
$group->any('/filters', App\Controllers\Web\Filters::class);
52-
$group->any('/orders', App\Controllers\Web\Orders::class);
59+
$group->any('/orders/{uuid}', App\Controllers\Web\Orders::class);
5360
$group->any('/cart[/{id}]', App\Controllers\Web\Cart::class);
5461
$group->any('/cart/{cart_id}/products[/{product_key}]', App\Controllers\Web\Cart\Products::class);
5562
}

core/src/Controllers/Security/Register.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,7 @@ class Register extends Controller
1111
public function post(): ResponseInterface
1212
{
1313
try {
14-
$user = new User();
15-
$properties = $this->getProperties();
16-
$properties['active'] = false;
17-
$properties['role_id'] = getenv('REGISTER_ROLE_ID') ?: 2;
18-
if (empty($properties['password'])) {
19-
$properties['password'] = bin2hex(random_bytes(20));
20-
}
21-
$user->fillData($properties);
22-
$user->save();
14+
$user = User::createUser($this->getProperties());
2315
} catch (\Exception $e) {
2416
return $this->failure($e->getMessage());
2517
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace App\Controllers\User;
4+
5+
use App\Models\UserAddress;
6+
use Illuminate\Database\Eloquent\Builder;
7+
use Vesp\Controllers\ModelGetController;
8+
9+
class Addresses extends ModelGetController
10+
{
11+
protected $scope = 'profile';
12+
protected $model = UserAddress::class;
13+
14+
protected function beforeGet(Builder $c): Builder
15+
{
16+
$c->where('user_id', $this->user->id);
17+
18+
return $c;
19+
}
20+
21+
protected function beforeCount(Builder $c): Builder
22+
{
23+
$c->where('user_id', $this->user->id);
24+
25+
return $c;
26+
}
27+
28+
protected function addSorting(Builder $c): Builder
29+
{
30+
$c->orderByDesc('created_at');
31+
32+
return $c;
33+
}
34+
}

core/src/Controllers/Web/Cart/Products.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ class Products extends ModelController
1818

1919
public function checkScope(string $method): ?ResponseInterface
2020
{
21+
if ($method === 'options') {
22+
return null;
23+
}
24+
2125
$id = $this->getProperty('cart_id');
2226
if (!$id || !$this->cart = Cart::query()->find($id)) {
2327
return $this->failure('', 404);

core/src/Controllers/Web/Orders.php

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,94 @@
22

33
namespace App\Controllers\Web;
44

5+
use App\Models\Cart;
6+
use App\Models\CartProduct;
57
use App\Models\Order;
6-
use App\Models\Product;
7-
use App\Services\Mail;
8+
use App\Models\OrderProduct;
9+
use App\Models\User;
10+
use App\Models\UserAddress;
811
use Psr\Http\Message\ResponseInterface;
912
use Vesp\Controllers\Controller;
1013

1114
class Orders extends Controller
1215
{
16+
17+
public function get(): ResponseInterface
18+
{
19+
$uuid = $this->getProperty('uuid');
20+
/** @var Order $order */
21+
if (!$uuid || !$order = Order::query()->where('uuid', $uuid)->first()) {
22+
return $this->failure('Not Found', 404);
23+
}
24+
25+
return $this->success($order->getData());
26+
}
27+
1328
public function put(): ResponseInterface
1429
{
15-
if (!$ordered = $this->getProperty('products')) {
16-
return $this->failure();
30+
$cartId = $this->getProperty('uuid');
31+
/** @var Cart $cart */
32+
if (!$cartId || !$cart = Cart::query()->find($cartId)) {
33+
return $this->failure('Not Found', 404);
1734
}
1835

19-
$orderTotal = 0;
20-
$orderProducts = [];
21-
foreach ($ordered as $id => $amount) {
22-
/** @var Product $product */
23-
if ($product = Product::query()->where('active', true)->find($id)) {
24-
$total = $product->price * $amount;
25-
$orderTotal += $total;
26-
$orderProducts[] = [
27-
'product_id' => $id,
28-
'title' => $product->title,
29-
'amount' => $amount,
30-
'price' => $product->price,
31-
'total' => $total,
32-
];
36+
$properties = $this->getProperties();
37+
if (!$user = $this->user) {
38+
try {
39+
$address = new UserAddress();
40+
$address->fillData($properties);
41+
42+
$properties['fullname'] = $properties['receiver'] ?? null;
43+
$properties['username'] = $properties['email'] ?? null;
44+
$user = User::createUser($properties);
45+
$address->user_id = $user->id;
46+
$address->save();
47+
} catch (\Exception $e) {
48+
return $this->failure($e->getMessage());
49+
}
50+
} elseif (empty($properties['address_id']) || !$address = $user->addresses()->find($properties['address_id'])) {
51+
try {
52+
$address = new UserAddress(['user_id' => $user->id]);
53+
$address->fillData($properties);
54+
$address->save();
55+
} catch (\Exception $e) {
56+
return $this->failure($e->getMessage());
3357
}
3458
}
3559

60+
$lang = $this->request->getHeaderLine('Content-Language') ?: 'ru';
61+
3662
$order = new Order();
37-
$order->fill($this->getProperties());
38-
$order->total = $orderTotal;
39-
if ($order->save()) {
40-
$order->orderProducts()->createMany($orderProducts);
41-
}
42-
// Use only if STMP is specified
43-
if ($order->email) {
44-
$error = (new Mail())->send(
45-
$order->email,
46-
'Спасибо за ваш заказ!',
47-
'email-order-new.tpl',
48-
['data' => $order->toArray()]
49-
);
50-
if ($error) {
51-
return $this->failure($error);
52-
}
63+
$order->user_id = $user->id;
64+
$order->address_id = $address->id;
65+
$order->comment = $properties['comment'] ?? null;
66+
$order->weight = 0;
67+
$order->cart = 0;
68+
$order->discount = 0;
69+
70+
$orderProducts = [];
71+
foreach ($cart->cartProducts()->orderBy('created_at')->cursor() as $cartProduct) {
72+
/** @var CartProduct $cartProduct */
73+
$orderProduct = new OrderProduct();
74+
$orderProduct->product_id = $cartProduct->product_id;
75+
$orderProduct->title = $cartProduct->product->getTitle($lang);
76+
$orderProduct->weight = $cartProduct->product->weight;
77+
$orderProduct->price = $cartProduct->product->price;
78+
$orderProduct->amount = $cartProduct->amount;
79+
$orderProduct->discount = 0;
80+
$orderProduct->options = $cartProduct->options;
81+
$orderProducts[] = $orderProduct;
82+
83+
$order->weight += $cartProduct->product->weight * $cartProduct->amount;
84+
$order->cart += $cartProduct->product->price * $cartProduct->amount;
5385
}
86+
$order->total = $order->cart;
87+
88+
$order->save();
89+
$order->orderProducts()->saveMany($orderProducts);
90+
91+
$order->sendEmails($lang);
5492

55-
return $this->success();
93+
return $this->success($order->toArray());
5694
}
5795
}

core/src/Models/Order.php

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Models;
44

5+
use App\Services\Mail;
56
use Carbon\Carbon;
67
use Illuminate\Database\Eloquent\Model;
78
use Illuminate\Database\Eloquent\Relations\BelongsTo;
@@ -43,7 +44,7 @@ protected static function booted(): void
4344
{
4445
static::saving(static function (self $model) {
4546
if (!$model->uuid) {
46-
$model->uuid = Uuid::uuid4();
47+
$model->uuid = (string)Uuid::uuid4();
4748
}
4849
if (!$model->created_at) {
4950
$model->created_at = Carbon::now();
@@ -92,4 +93,38 @@ public function calculate(): void
9293
$this->total = max($total, 0);
9394
$this->save();
9495
}
96+
97+
public function getData(): array
98+
{
99+
return [
100+
'order' => $this->toArray(),
101+
'user' => $this->user->toArray(),
102+
'address' => $this->address->toArray(),
103+
'products' => $this->orderProducts()
104+
->with('product:id,uri', 'product.translations:product_id,lang,title', 'product.firstFile')
105+
->get()
106+
->toArray(),
107+
];
108+
}
109+
110+
public function sendEmails(?string $lang = 'ru'): ?string
111+
{
112+
$data = $this->getData();
113+
$data['lang'] = $lang;
114+
115+
if ($emailAdmin = getenv('EMAIL_ADMIN')) {
116+
$mail = new Mail();
117+
$subject = getenv('EMAIL_SUBJECT_ORDER_NEW_ADMIN_' . strtoupper($lang));
118+
if ($error = $mail->send($emailAdmin, $subject, 'email-order-new-admin', $data)) {
119+
return $error;
120+
}
121+
}
122+
123+
$subject = getenv('EMAIL_SUBJECT_ORDER_NEW_USER_' . strtoupper($lang));
124+
if ($error = $this->user->sendEmail($subject, 'email-order-new-user', $data)) {
125+
return $error;
126+
}
127+
128+
return null;
129+
}
95130
}

core/src/Models/User.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,4 +184,18 @@ public function fillData($data): User
184184

185185
return $this;
186186
}
187+
188+
public static function createUser(array $properties): User
189+
{
190+
$user = new User();
191+
$properties['active'] = false;
192+
$properties['role_id'] = getenv('REGISTER_ROLE_ID') ?: 2;
193+
if (empty($properties['password'])) {
194+
$properties['password'] = bin2hex(random_bytes(20));
195+
}
196+
$user->fillData($properties);
197+
$user->save();
198+
199+
return $user;
200+
}
187201
}

core/src/Models/UserAddress.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Illuminate\Database\Eloquent\Model;
77
use Illuminate\Database\Eloquent\Relations\BelongsTo;
88
use Illuminate\Database\Eloquent\Relations\HasMany;
9+
use RuntimeException;
910

1011
/**
1112
* @property int $id
@@ -15,7 +16,6 @@
1516
* @property ?string $phone
1617
* @property ?string $address
1718
* @property ?string $country
18-
* @property ?bool $gender
1919
* @property ?string $company
2020
* @property ?string $city
2121
* @property ?string $zip
@@ -40,8 +40,24 @@ public function orders(): HasMany
4040
return $this->hasMany(Order::class);
4141
}
4242

43-
public function getFullAddressAttribute()
43+
public function getFullAddressAttribute(): string
4444
{
4545
return implode(', ', array_filter([$this->receiver, $this->zip, $this->city, $this->address]));
4646
}
47+
48+
public function fillData(array $data): UserAddress
49+
{
50+
$required = ['receiver', 'address', 'zip', 'city', 'phone', 'email'];
51+
foreach ($required as $key) {
52+
if (empty($data[$key])) {
53+
throw new RuntimeException('errors.address.no_' . $key);
54+
}
55+
if ($key === 'email' && !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
56+
throw new RuntimeException('errors.address.wrong_email');
57+
}
58+
}
59+
$this->fill($data);
60+
61+
return $this;
62+
}
4763
}

0 commit comments

Comments
 (0)