From d6e5c7481aaa501b87c04d085cd3d2e04abd6f7d Mon Sep 17 00:00:00 2001 From: bezumkin Date: Wed, 6 Jul 2022 14:04:33 +0700 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/db/migrations/20220705002400_orders.php | 49 +++++++++++ core/db/seeds/UserRoles.php | 18 ++-- core/routes.php | 2 + core/src/Controllers/Admin/Orders.php | 43 +++++++++ core/src/Controllers/Web/Orders.php | 44 ++++++++++ core/src/Models/Order.php | 34 ++++++++ core/src/Models/OrderProduct.php | 34 ++++++++ frontend/src/admin/components/forms/order.vue | 76 ++++++++++++++++ frontend/src/admin/lexicons/de.js | 11 +++ frontend/src/admin/lexicons/en.js | 11 +++ frontend/src/admin/lexicons/ru.js | 11 +++ frontend/src/admin/pages/orders.vue | 65 ++++++++++++++ frontend/src/admin/pages/orders/edit/_id.vue | 43 +++++++++ frontend/src/admin/plugins/menu.js | 5 ++ frontend/src/site/assets/scss/index.scss | 1 + frontend/src/site/components/app/navbar.vue | 4 +- frontend/src/site/components/cart.vue | 10 +-- frontend/src/site/components/order.vue | 87 +++++++++++++++++++ frontend/src/site/nuxt.config.js | 4 + frontend/src/site/store/index.js | 11 +++ 20 files changed, 544 insertions(+), 19 deletions(-) create mode 100644 core/db/migrations/20220705002400_orders.php create mode 100644 core/src/Controllers/Admin/Orders.php create mode 100644 core/src/Controllers/Web/Orders.php create mode 100644 core/src/Models/Order.php create mode 100644 core/src/Models/OrderProduct.php create mode 100644 frontend/src/admin/components/forms/order.vue create mode 100644 frontend/src/admin/pages/orders.vue create mode 100644 frontend/src/admin/pages/orders/edit/_id.vue create mode 100644 frontend/src/site/components/order.vue diff --git a/core/db/migrations/20220705002400_orders.php b/core/db/migrations/20220705002400_orders.php new file mode 100644 index 0000000..2bf74e9 --- /dev/null +++ b/core/db/migrations/20220705002400_orders.php @@ -0,0 +1,49 @@ +schema->create( + 'orders', + function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('email'); + $table->char('post', 6)->nullable(); + $table->string('city')->nullable(); + $table->string('address')->nullable(); + $table->boolean('paid')->default(false); + $table->unsignedDecimal('total')->nullable(); + $table->timestamps(); + $table->timestamp('paid_at')->nullable(); + } + ); + + $this->schema->create( + 'order_products', + function (Blueprint $table) { + $table->id(); + $table->foreignId('order_id') + ->constrained('orders')->cascadeOnDelete(); + $table->foreignId('product_id')->nullable() + ->constrained('products')->nullOnDelete(); + $table->string('title'); + $table->unsignedDecimal('price'); + $table->unsignedInteger('amount')->default(1); + $table->unsignedDecimal('total'); + } + ); + } + + public function down(): void + { + $this->schema->drop('order_products'); + $this->schema->drop('orders'); + } +} diff --git a/core/db/seeds/UserRoles.php b/core/db/seeds/UserRoles.php index 445c4d4..5b1aa2d 100644 --- a/core/db/seeds/UserRoles.php +++ b/core/db/seeds/UserRoles.php @@ -1,20 +1,20 @@ [ - 'scope' => ['profile', 'users', 'products'], - ], - 'User' => [ - 'scope' => ['profile'], - ], -]; + $roles = [ + 'Administrator' => [ + 'scope' => ['profile', 'users', 'products', 'orders'], + ], + 'User' => [ + 'scope' => ['profile'], + ], + ]; foreach ($roles as $title => $data) { if (!$group = UserRole::query()->where('title', $title)->first()) { diff --git a/core/routes.php b/core/routes.php index 9e1c961..ed51141 100644 --- a/core/routes.php +++ b/core/routes.php @@ -25,6 +25,7 @@ static function (RouteCollectorProxy $group) { $group->any('/categories[/{id}]', App\Controllers\Admin\Categories::class); $group->any('/products[/{id}]', App\Controllers\Admin\Products::class); $group->any('/product/{product_id}/files[/{file_id}]', App\Controllers\Admin\Product\Files::class); + $group->any('/orders[/{id}]', App\Controllers\Admin\Orders::class); } ); @@ -34,6 +35,7 @@ static function (RouteCollectorProxy $group) { $group->any('/categories[/{alias}]', App\Controllers\Web\Categories::class); $group->any('/categories/{category}/products[/{alias}]', App\Controllers\Web\Category\Products::class); $group->any('/products', App\Controllers\Web\Products::class); + $group->any('/orders', App\Controllers\Web\Orders::class); } ); } diff --git a/core/src/Controllers/Admin/Orders.php b/core/src/Controllers/Admin/Orders.php new file mode 100644 index 0000000..368e8e7 --- /dev/null +++ b/core/src/Controllers/Admin/Orders.php @@ -0,0 +1,43 @@ +with('orderProducts'); + + return $c; + } + + protected function beforeSave(Model $record): ?ResponseInterface + { + /** @var Order $record */ + if ($record->paid && !$record->paid_at) { + $record->paid_at = time(); + } elseif ($record->paid_at && !$record->paid) { + $record->paid_at = null; + } + + return null; + } + + protected function beforeCount(Builder $c): Builder + { + if ($query = $this->getProperty('query')) { + $c->where('title', 'LIKE', "%$query%"); + } + + return $c; + } +} \ No newline at end of file diff --git a/core/src/Controllers/Web/Orders.php b/core/src/Controllers/Web/Orders.php new file mode 100644 index 0000000..b653f27 --- /dev/null +++ b/core/src/Controllers/Web/Orders.php @@ -0,0 +1,44 @@ +getProperty('products')) { + return $this->failure(); + } + + $orderTotal = 0; + $orderProducts = []; + foreach ($ordered as $id => $amount) { + /** @var Product $product */ + if ($product = Product::query()->where('active', true)->find($id)) { + $total = $product->price * $amount; + $orderTotal += $total; + $orderProducts[] = [ + 'product_id' => $id, + 'title' => $product->title, + 'amount' => $amount, + 'price' => $product->price, + 'total' => $total, + ]; + } + } + + $order = new Order(); + $order->fill($this->getProperties()); + $order->total = $orderTotal; + if ($order->save()) { + $order->orderProducts()->createMany($orderProducts); + } + + return $this->success(); + } +} \ No newline at end of file diff --git a/core/src/Models/Order.php b/core/src/Models/Order.php new file mode 100644 index 0000000..bcd2eb3 --- /dev/null +++ b/core/src/Models/Order.php @@ -0,0 +1,34 @@ + 'boolean']; + protected $guarded = ['id', 'created_at', 'updated_at', 'paid_at']; + protected $dates = ['paid_at']; + + public function orderProducts(): HasMany + { + return $this->hasMany(OrderProduct::class); + } +} \ No newline at end of file diff --git a/core/src/Models/OrderProduct.php b/core/src/Models/OrderProduct.php new file mode 100644 index 0000000..0c2e9fd --- /dev/null +++ b/core/src/Models/OrderProduct.php @@ -0,0 +1,34 @@ +belongsTo(Order::class); + } + + public function product(): BelongsTo + { + return $this->belongsTo(Product::class); + } +} \ No newline at end of file diff --git a/frontend/src/admin/components/forms/order.vue b/frontend/src/admin/components/forms/order.vue new file mode 100644 index 0000000..79c052d --- /dev/null +++ b/frontend/src/admin/components/forms/order.vue @@ -0,0 +1,76 @@ + + + diff --git a/frontend/src/admin/lexicons/de.js b/frontend/src/admin/lexicons/de.js index 5b80c13..c9f9ec9 100644 --- a/frontend/src/admin/lexicons/de.js +++ b/frontend/src/admin/lexicons/de.js @@ -56,6 +56,17 @@ export default { category: 'Kategorie', active: 'Aktiv', }, + order: { + title_one: 'Befehl', + title_many: 'Aufträge', + name: 'Kunde', + email: 'Email', + post: 'Post', + city: 'Stadt', + address: 'Adresse', + paid: 'Bezahlt', + total: 'Gesamt', + }, }, errors: { security: { diff --git a/frontend/src/admin/lexicons/en.js b/frontend/src/admin/lexicons/en.js index 15ccce6..6b9ff3e 100644 --- a/frontend/src/admin/lexicons/en.js +++ b/frontend/src/admin/lexicons/en.js @@ -56,6 +56,17 @@ export default { category: 'Category', active: 'Active', }, + order: { + title_one: 'Order', + title_many: 'Orders', + name: 'Customer', + email: 'Email', + post: 'Post', + city: 'City', + address: 'Address', + paid: 'Paid', + total: 'Total', + }, }, errors: { security: { diff --git a/frontend/src/admin/lexicons/ru.js b/frontend/src/admin/lexicons/ru.js index 071ab07..331d45d 100644 --- a/frontend/src/admin/lexicons/ru.js +++ b/frontend/src/admin/lexicons/ru.js @@ -56,6 +56,17 @@ export default { category: 'Категория', active: 'Включено', }, + order: { + title_one: 'Заказ', + title_many: 'Заказы', + name: 'Имя покупателя', + email: 'Email', + post: 'Индекс', + city: 'Город', + address: 'Адрес', + paid: 'Оплачено', + total: 'Стоимость', + }, }, errors: { security: { diff --git a/frontend/src/admin/pages/orders.vue b/frontend/src/admin/pages/orders.vue new file mode 100644 index 0000000..338a2fb --- /dev/null +++ b/frontend/src/admin/pages/orders.vue @@ -0,0 +1,65 @@ + + + diff --git a/frontend/src/admin/pages/orders/edit/_id.vue b/frontend/src/admin/pages/orders/edit/_id.vue new file mode 100644 index 0000000..d0d00fa --- /dev/null +++ b/frontend/src/admin/pages/orders/edit/_id.vue @@ -0,0 +1,43 @@ + + + diff --git a/frontend/src/admin/plugins/menu.js b/frontend/src/admin/plugins/menu.js index 1418d89..144927a 100644 --- a/frontend/src/admin/plugins/menu.js +++ b/frontend/src/admin/plugins/menu.js @@ -9,6 +9,11 @@ export default [ title: 'models.category.title_many', scope: 'products', }, + { + name: 'orders', + title: 'models.order.title_many', + scope: 'orders', + }, { name: 'users', title: 'models.user.title_many', diff --git a/frontend/src/site/assets/scss/index.scss b/frontend/src/site/assets/scss/index.scss index c4e60df..fb80156 100644 --- a/frontend/src/site/assets/scss/index.scss +++ b/frontend/src/site/assets/scss/index.scss @@ -15,6 +15,7 @@ @import '~bootstrap/scss/modal'; @import '~bootstrap/scss/close'; @import '~bootstrap/scss/transitions'; +@import '~bootstrap/scss/forms'; @import '~bootstrap/scss/utilities/sizing'; @import '~bootstrap/scss/utilities/text'; @import '~bootstrap/scss/utilities/flex'; diff --git a/frontend/src/site/components/app/navbar.vue b/frontend/src/site/components/app/navbar.vue index d25cb76..aad1ce9 100644 --- a/frontend/src/site/components/app/navbar.vue +++ b/frontend/src/site/components/app/navbar.vue @@ -12,16 +12,18 @@ + diff --git a/frontend/src/site/nuxt.config.js b/frontend/src/site/nuxt.config.js index db33e2f..33e3cd2 100644 --- a/frontend/src/site/nuxt.config.js +++ b/frontend/src/site/nuxt.config.js @@ -62,6 +62,10 @@ Config.bootstrapVue.componentPlugins = [ 'CarouselPlugin', 'BreadcrumbPlugin', 'ModalPlugin', + 'FormPlugin', + 'FormGroupPlugin', + 'FormInputPlugin', + 'SpinnerPlugin', ] export default Config diff --git a/frontend/src/site/store/index.js b/frontend/src/site/store/index.js index 3cfe0c4..c1c0269 100644 --- a/frontend/src/site/store/index.js +++ b/frontend/src/site/store/index.js @@ -31,6 +31,17 @@ export const getters = { }) return total ? total.toFixed(2) : 0 }, + products(state) { + const products = {} + state.cart.forEach((i) => { + if (!products[i.id]) { + products[i.id] = {...i, amount: 1} + } else { + products[i.id].amount += 1 + } + }) + return Object.values(products) + }, } export const actions = {