瀏覽代碼

feat: export customer

Muhammad Iqbal Afandi 3 年之前
父節點
當前提交
f64b1badd6

+ 43
- 0
app/Exports/CustomersExport.php 查看文件

@@ -0,0 +1,43 @@
1
+<?php
2
+
3
+namespace App\Exports;
4
+
5
+use App\Models\Customer;
6
+use Illuminate\Contracts\Support\Responsable;
7
+use Illuminate\Contracts\View\View;
8
+use Illuminate\Http\Request;
9
+use Maatwebsite\Excel\Concerns\Exportable;
10
+use Maatwebsite\Excel\Concerns\FromView;
11
+use Maatwebsite\Excel\Concerns\ShouldAutoSize;
12
+use Maatwebsite\Excel\Concerns\WithStyles;
13
+use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
14
+
15
+class CustomersExport implements ShouldAutoSize, Responsable, FromView, WithStyles
16
+{
17
+    use Exportable;
18
+
19
+    private $fileName = 'customers-report.xls';
20
+
21
+    public function __construct(private Request $request)
22
+    {}
23
+
24
+    public function view(): View
25
+    {
26
+        $customers = Customer::filter($this->request->only('search'))->get();
27
+        return view('excel.customer-report', compact('customers'));
28
+    }
29
+
30
+    public function styles(Worksheet $sheet)
31
+    {
32
+        return [
33
+            1 => [
34
+                'font' => ['bold' => true, 'size' => 12],
35
+                'alignment' => ['vertical' => 'center', 'horizontal' => 'center'],
36
+            ],
37
+            3 => [
38
+                'font' => ['bold' => true],
39
+            ],
40
+            'E' => ['alignment' => ['horizontal' => 'left']],
41
+        ];
42
+    }
43
+}

+ 13
- 0
app/Http/Controllers/CustomerController.php 查看文件

@@ -2,10 +2,13 @@
2 2
 
3 3
 namespace App\Http\Controllers;
4 4
 
5
+use App\Exports\CustomersExport;
5 6
 use App\Http\Controllers\Controller;
6 7
 use App\Http\Requests\Customer\StoreCustomerRequest;
7 8
 use App\Http\Requests\Customer\UpdateCustomerRequest;
8 9
 use App\Models\Customer;
10
+use App\Models\Transaction;
11
+use App\Services\TransactionService;
9 12
 
10 13
 class CustomerController extends Controller
11 14
 {
@@ -117,6 +120,8 @@ class CustomerController extends Controller
117 120
                         'transactionStatusId' => $transaction->transactionStatus->id,
118 121
                     ]),
119 122
                 'totalTransaction' => $customer->transaction->count(),
123
+                'totalValue' => (new TransactionService)->totalPriceGroupAsString($customer->fresh()->transaction),
124
+                'totalDiscountGiven' => (new TransactionService)->totalDiscountGivenGroupAsString($customer->fresh()->transaction),
120 125
             ],
121 126
         ]);
122 127
     }
@@ -147,4 +152,12 @@ class CustomerController extends Controller
147 152
 
148 153
         return to_route('customers.index')->with('success', __('messages.success.destroy.customer'));
149 154
     }
155
+
156
+    /**
157
+     * Export to excel
158
+     */
159
+    public function exportExcel()
160
+    {
161
+        return new CustomersExport(request());
162
+    }
150 163
 }

+ 3
- 4
app/Models/Transaction.php 查看文件

@@ -118,11 +118,10 @@ class Transaction extends Model
118 118
 
119 119
     public function totalDiscountGiven()
120 120
     {
121
-        $totalDiscountGiven = $this->getRawOriginal('discount') - $this->subTotal();
122
-        if ($totalDiscountGiven < 0) {
123
-            return abs($totalDiscountGiven);
121
+        if ($this->getRawOriginal('discount') >= $this->subTotal()) {
122
+            return $this->subTotal();
124 123
         } else {
125
-            return $totalDiscountGiven;
124
+            return $this->getRawOriginal('discount');
126 125
         }
127 126
     }
128 127
 

+ 11
- 1
app/Services/TransactionService.php 查看文件

@@ -38,9 +38,19 @@ class TransactionService extends CurrencyFormatService
38 38
         return $this->setRupiahFormat($this->totalPriceGroup($collections), true);
39 39
     }
40 40
 
41
+    public function totalDiscountGiven(EloquentCollection $collections)
42
+    {
43
+        return $collections->transform(fn($collect) => $collect->totalDiscountGiven());
44
+    }
45
+
46
+    public function totalDiscountGivenGroup(EloquentCollection $collections)
47
+    {
48
+        return $this->totalDiscountGiven($collections)->sum();
49
+    }
50
+
41 51
     public function totalDiscountGivenGroupAsString(EloquentCollection $collections)
42 52
     {
43
-        return $this->setRupiahFormat($collections->sum(fn($collect) => $collect->totalDiscountGiven()), true);
53
+        return $this->setRupiahFormat($this->totalDiscountGivenGroup($collections), true);
44 54
     }
45 55
 
46 56
     public function totalPerMonth(EloquentCollection $collections)

+ 1
- 1
lang/id/words.php 查看文件

@@ -20,7 +20,7 @@ return [
20 20
     'today' => 'Hari ini',
21 21
     'this_month' => 'Bulan ini',
22 22
     'total' => 'Total',
23
-    'discount_given' => 'Diskon yang diberikan',
23
+    'discount_given' => 'Diskon diberikan',
24 24
     'transaction' => 'Transaksi',
25 25
     'expense' => 'Pengeluaran',
26 26
     'laundry_type' => 'Jenis Laundry',

+ 49
- 7
public/js/resources_js_pages_customer_Edit_vue.js 查看文件

@@ -1539,7 +1539,7 @@ var _hoisted_12 = {
1539 1539
   "class": "grid mt-3 ml-1"
1540 1540
 };
1541 1541
 var _hoisted_13 = {
1542
-  "class": "col-auto"
1542
+  "class": "col-auto mr-7"
1543 1543
 };
1544 1544
 
1545 1545
 var _hoisted_14 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", {
@@ -1558,15 +1558,53 @@ var _hoisted_16 = {
1558 1558
   "class": "text-xl font-bold"
1559 1559
 };
1560 1560
 var _hoisted_17 = {
1561
+  "class": "col-auto mr-7"
1562
+};
1563
+
1564
+var _hoisted_18 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", {
1565
+  "class": "text-base"
1566
+}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", {
1567
+  "class": "pi pi-shopping-cart"
1568
+}), /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Total Nilai")], -1
1569
+/* HOISTED */
1570
+);
1571
+
1572
+var _hoisted_19 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("br", null, null, -1
1573
+/* HOISTED */
1574
+);
1575
+
1576
+var _hoisted_20 = {
1577
+  "class": "text-xl font-bold"
1578
+};
1579
+var _hoisted_21 = {
1580
+  "class": "col-auto"
1581
+};
1582
+
1583
+var _hoisted_22 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", {
1584
+  "class": "text-base"
1585
+}, [/*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("i", {
1586
+  "class": "pi pi-shopping-cart"
1587
+}), /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createTextVNode)(" Total Diskon didapatkan")], -1
1588
+/* HOISTED */
1589
+);
1590
+
1591
+var _hoisted_23 = /*#__PURE__*/(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("br", null, null, -1
1592
+/* HOISTED */
1593
+);
1594
+
1595
+var _hoisted_24 = {
1596
+  "class": "text-xl font-bold"
1597
+};
1598
+var _hoisted_25 = {
1561 1599
   "class": "grid"
1562 1600
 };
1563
-var _hoisted_18 = {
1601
+var _hoisted_26 = {
1564 1602
   "class": "col-12"
1565 1603
 };
1566
-var _hoisted_19 = {
1604
+var _hoisted_27 = {
1567 1605
   "class": "font-bold"
1568 1606
 };
1569
-var _hoisted_20 = {
1607
+var _hoisted_28 = {
1570 1608
   "class": "font-bold"
1571 1609
 };
1572 1610
 function render(_ctx, _cache, $props, $setup, $data, $options) {
@@ -1660,7 +1698,11 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
1660 1698
 
1661 1699
       })])]), _hoisted_11, $props.transactions.totalTransaction ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_12, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_13, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, [_hoisted_14, _hoisted_15, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_16, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.transactions.totalTransaction), 1
1662 1700
       /* TEXT */
1663
-      )])])])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_17, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_18, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_Card, null, {
1701
+      )])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_17, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, [_hoisted_18, _hoisted_19, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_20, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.transactions.totalValue), 1
1702
+      /* TEXT */
1703
+      )])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_21, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("h2", null, [_hoisted_22, _hoisted_23, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("span", _hoisted_24, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)($props.transactions.totalDiscountGiven), 1
1704
+      /* TEXT */
1705
+      )])])])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_25, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_26, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_Card, null, {
1664 1706
         content: (0,vue__WEBPACK_IMPORTED_MODULE_0__.withCtx)(function () {
1665 1707
           return [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_DataTable, {
1666 1708
             "responsive-layout": "scroll",
@@ -1681,7 +1723,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
1681 1723
                         field = _ref.field;
1682 1724
                     return [field === 'transactionNumber' ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
1683 1725
                       key: 0
1684
-                    }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", _hoisted_19, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data[field]), 1
1726
+                    }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", _hoisted_27, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data[field]), 1
1685 1727
                     /* TEXT */
1686 1728
                     ), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data.createdAt), 1
1687 1729
                     /* TEXT */
@@ -1689,7 +1731,7 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
1689 1731
                     /* STABLE_FRAGMENT */
1690 1732
                     )) : field === 'customer' ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)(vue__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
1691 1733
                       key: 1
1692
-                    }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", _hoisted_20, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data.customer.number), 1
1734
+                    }, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", _hoisted_28, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data.customer.number), 1
1693 1735
                     /* TEXT */
1694 1736
                     ), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("p", null, (0,vue__WEBPACK_IMPORTED_MODULE_0__.toDisplayString)(data.customer.name), 1
1695 1737
                     /* TEXT */

+ 24
- 5
public/js/resources_js_pages_customer_Index_vue.js 查看文件

@@ -424,14 +424,18 @@ __webpack_require__.r(__webpack_exports__);
424 424
       }), {
425 425
         preserveState: true
426 426
       });
427
+      var params = window.location.search;
428
+      exportExcelLink.value = "/reports/customers/export/excel".concat(params);
427 429
     }, 300));
430
+    var exportExcelLink = (0,vue__WEBPACK_IMPORTED_MODULE_0__.ref)('/reports/customers/export/excel');
428 431
     var __returned__ = {
429 432
       props: props,
430 433
       filterForm: filterForm,
434
+      exportExcelLink: exportExcelLink,
431 435
       watch: vue__WEBPACK_IMPORTED_MODULE_0__.watch,
436
+      ref: vue__WEBPACK_IMPORTED_MODULE_0__.ref,
432 437
       Inertia: _inertiajs_inertia__WEBPACK_IMPORTED_MODULE_1__.Inertia,
433 438
       Head: _inertiajs_inertia_vue3__WEBPACK_IMPORTED_MODULE_2__.Head,
434
-      Link: _inertiajs_inertia_vue3__WEBPACK_IMPORTED_MODULE_2__.Link,
435 439
       useForm: _inertiajs_inertia_vue3__WEBPACK_IMPORTED_MODULE_2__.useForm,
436 440
       throttle: (lodash_throttle__WEBPACK_IMPORTED_MODULE_3___default()),
437 441
       pickBy: (lodash_pickBy__WEBPACK_IMPORTED_MODULE_4___default()),
@@ -1081,9 +1085,16 @@ var _hoisted_3 = {
1081 1085
   "class": "col-12 md:col-8"
1082 1086
 };
1083 1087
 var _hoisted_4 = {
1084
-  "class": "flex align-items-center"
1088
+  "class": "grid"
1085 1089
 };
1086 1090
 var _hoisted_5 = {
1091
+  "class": "col-12 md:col-3"
1092
+};
1093
+var _hoisted_6 = {
1094
+  key: 0,
1095
+  "class": "col-12 md:col-3"
1096
+};
1097
+var _hoisted_7 = {
1087 1098
   "class": "col-12 md:col-4 flex flex-column md:flex-row justify-content-end"
1088 1099
 };
1089 1100
 function render(_ctx, _cache, $props, $setup, $data, $options) {
@@ -1105,8 +1116,8 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
1105 1116
         stripedRows: true
1106 1117
       }, {
1107 1118
         header: (0,vue__WEBPACK_IMPORTED_MODULE_0__.withCtx)(function () {
1108
-          return [_hoisted_1, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_3, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_InputText, {
1109
-            "class": "w-full md:w-27rem",
1119
+          return [_hoisted_1, (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_2, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_3, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_4, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_5, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)(_component_InputText, {
1120
+            "class": "w-full",
1110 1121
             placeholder: "cari...",
1111 1122
             modelValue: $setup.filterForm.search,
1112 1123
             "onUpdate:modelValue": _cache[0] || (_cache[0] = function ($event) {
@@ -1114,7 +1125,15 @@ function render(_ctx, _cache, $props, $setup, $data, $options) {
1114 1125
             })
1115 1126
           }, null, 8
1116 1127
           /* PROPS */
1117
-          , ["modelValue"])])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_5, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup["AppButton"], {
1128
+          , ["modelValue"])]), $props.customers.data ? ((0,vue__WEBPACK_IMPORTED_MODULE_0__.openBlock)(), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementBlock)("div", _hoisted_6, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup["AppButton"], {
1129
+            label: "Export excel",
1130
+            "class-button": "p-button-outlined w-full md:w-16rem",
1131
+            icon: "pi pi-file-excel",
1132
+            "inertia-link": false,
1133
+            href: $setup.exportExcelLink
1134
+          }, null, 8
1135
+          /* PROPS */
1136
+          , ["href"])])) : (0,vue__WEBPACK_IMPORTED_MODULE_0__.createCommentVNode)("v-if", true)])]), (0,vue__WEBPACK_IMPORTED_MODULE_0__.createElementVNode)("div", _hoisted_7, [(0,vue__WEBPACK_IMPORTED_MODULE_0__.createVNode)($setup["AppButton"], {
1118 1137
             href: _ctx.route('customers.create'),
1119 1138
             label: "Tambah Customer",
1120 1139
             icon: "pi pi-pencil",

+ 1
- 1
public/js/vue.js 查看文件

@@ -58088,7 +58088,7 @@ module.exports = JSON.parse('{"name":"axios","version":"0.21.4","description":"P
58088 58088
 /******/ 		// This function allow to reference async chunks
58089 58089
 /******/ 		__webpack_require__.u = (chunkId) => {
58090 58090
 /******/ 			// return url for filenames based on template
58091
-/******/ 			return "js/" + chunkId + ".js?id=" + {"node_modules_chart_js_auto_auto_esm_js":"10c6b388645ceb22","resources_js_pages_auth_ForgotPassword_vue":"06e3fde2f6b5dfa3","resources_js_pages_auth_Login_vue":"0d70b4f828bb2ae3","resources_js_pages_auth_ResetPassword_vue":"2ba70d514b47ecff","resources_js_pages_auth_VerifyEmail_vue":"ebac28cf5fb51cfc","resources_js_pages_customer_Create_vue":"1220be5949d46569","resources_js_pages_customer_Edit_vue":"9b1098714289a805","resources_js_pages_customer_Index_vue":"89aeb69bc7bf9125","resources_js_pages_customer_TableHeader_js":"71be5afdca048a9c","resources_js_pages_discount_Index_vue":"7a73e2119e6e6c6f","resources_js_pages_error_Error_vue":"39121f9961877130","resources_js_pages_expense_Create_vue":"8fa047c8fcff0fa3","resources_js_pages_expense_Index_vue":"b56d8a0027fef24c","resources_js_pages_expense_Show_vue":"e46cf4a28b9e732b","resources_js_pages_expense_TableHeader_js":"72e3dee74175b1c0","resources_js_pages_home_Index_vue":"2e900ea05a1e7b5c","resources_js_pages_laundry_Create_vue":"f5731b3f078c4bff","resources_js_pages_laundry_Edit_vue":"430f285b197d2fc1","resources_js_pages_laundry_Index_vue":"ee761f9e7d6e4502","resources_js_pages_laundry_TableHeader_js":"494e577855bbcaf6","resources_js_pages_mutation_Report_vue":"0c16f00427eb4815","resources_js_pages_mutation_TableHeader_js":"82c2999bd7d098a1","resources_js_pages_outlet_Create_vue":"4958b1a88d1e03d1","resources_js_pages_outlet_Edit_vue":"3ce4dea5bd8e134a","resources_js_pages_outlet_Index_vue":"f58972cb6db52f4a","resources_js_pages_outlet_TableHeader_js":"498bf7e64bc0d0c4","resources_js_pages_product_Create_vue":"6f7ae2bf0addfd2c","resources_js_pages_product_Edit_vue":"aec56d000e33fbe6","resources_js_pages_product_Index_vue":"e73d3cd965bdbfb3","resources_js_pages_product_TableHeader_js":"b8eaaa9de25a2322","resources_js_pages_transaction_Create_vue":"04881653c83db0e8","resources_js_pages_transaction_Index_vue":"54a40dce85162abd","resources_js_pages_transaction_Report_vue":"a3646e1ede56ed0d","resources_js_pages_transaction_Show_vue":"bc1cb7b5161b5386","resources_js_pages_transaction_TableHeader_js":"be63e672e103818b","resources_js_pages_user_Create_vue":"9328027e33f14038","resources_js_pages_user_Edit_vue":"5e97bc1dbb553877","resources_js_pages_user_Index_vue":"bc60d10f530734f1","resources_js_pages_user_Show_vue":"0acbc3d158904cf1","resources_js_pages_user_TableHeader_js":"5653ecbcd70fd235"}[chunkId] + "";
58091
+/******/ 			return "js/" + chunkId + ".js?id=" + {"node_modules_chart_js_auto_auto_esm_js":"10c6b388645ceb22","resources_js_pages_auth_ForgotPassword_vue":"06e3fde2f6b5dfa3","resources_js_pages_auth_Login_vue":"0d70b4f828bb2ae3","resources_js_pages_auth_ResetPassword_vue":"2ba70d514b47ecff","resources_js_pages_auth_VerifyEmail_vue":"ebac28cf5fb51cfc","resources_js_pages_customer_Create_vue":"1220be5949d46569","resources_js_pages_customer_Edit_vue":"bb71c64039e173a1","resources_js_pages_customer_Index_vue":"52a1110802b6b996","resources_js_pages_customer_TableHeader_js":"71be5afdca048a9c","resources_js_pages_discount_Index_vue":"7a73e2119e6e6c6f","resources_js_pages_error_Error_vue":"39121f9961877130","resources_js_pages_expense_Create_vue":"8fa047c8fcff0fa3","resources_js_pages_expense_Index_vue":"b56d8a0027fef24c","resources_js_pages_expense_Show_vue":"e46cf4a28b9e732b","resources_js_pages_expense_TableHeader_js":"72e3dee74175b1c0","resources_js_pages_home_Index_vue":"2e900ea05a1e7b5c","resources_js_pages_laundry_Create_vue":"f5731b3f078c4bff","resources_js_pages_laundry_Edit_vue":"430f285b197d2fc1","resources_js_pages_laundry_Index_vue":"ee761f9e7d6e4502","resources_js_pages_laundry_TableHeader_js":"494e577855bbcaf6","resources_js_pages_mutation_Report_vue":"0c16f00427eb4815","resources_js_pages_mutation_TableHeader_js":"82c2999bd7d098a1","resources_js_pages_outlet_Create_vue":"4958b1a88d1e03d1","resources_js_pages_outlet_Edit_vue":"3ce4dea5bd8e134a","resources_js_pages_outlet_Index_vue":"f58972cb6db52f4a","resources_js_pages_outlet_TableHeader_js":"498bf7e64bc0d0c4","resources_js_pages_product_Create_vue":"6f7ae2bf0addfd2c","resources_js_pages_product_Edit_vue":"aec56d000e33fbe6","resources_js_pages_product_Index_vue":"e73d3cd965bdbfb3","resources_js_pages_product_TableHeader_js":"b8eaaa9de25a2322","resources_js_pages_transaction_Create_vue":"04881653c83db0e8","resources_js_pages_transaction_Index_vue":"54a40dce85162abd","resources_js_pages_transaction_Report_vue":"a3646e1ede56ed0d","resources_js_pages_transaction_Show_vue":"bc1cb7b5161b5386","resources_js_pages_transaction_TableHeader_js":"be63e672e103818b","resources_js_pages_user_Create_vue":"9328027e33f14038","resources_js_pages_user_Edit_vue":"5e97bc1dbb553877","resources_js_pages_user_Index_vue":"bc60d10f530734f1","resources_js_pages_user_Show_vue":"0acbc3d158904cf1","resources_js_pages_user_TableHeader_js":"5653ecbcd70fd235"}[chunkId] + "";
58092 58092
 /******/ 		};
58093 58093
 /******/ 	})();
58094 58094
 /******/ 	

+ 19
- 1
resources/js/pages/customer/Edit.vue 查看文件

@@ -113,7 +113,7 @@ const onCancel = () => (visibleDialog.value = false)
113 113
 
114 114
     <h2>Riwayat Transaksi</h2>
115 115
     <div v-if="transactions.totalTransaction" class="grid mt-3 ml-1">
116
-      <div class="col-auto">
116
+      <div class="col-auto mr-7">
117 117
         <h2>
118 118
           <span class="text-base"> <i class="pi pi-shopping-cart" /> Total Transaksi</span>
119 119
 
@@ -122,6 +122,24 @@ const onCancel = () => (visibleDialog.value = false)
122 122
           <span class="text-xl font-bold">{{ transactions.totalTransaction }}</span>
123 123
         </h2>
124 124
       </div>
125
+      <div class="col-auto mr-7">
126
+        <h2>
127
+          <span class="text-base"> <i class="pi pi-shopping-cart" /> Total Nilai</span>
128
+
129
+          <br />
130
+
131
+          <span class="text-xl font-bold">{{ transactions.totalValue }}</span>
132
+        </h2>
133
+      </div>
134
+      <div class="col-auto">
135
+        <h2>
136
+          <span class="text-base"> <i class="pi pi-shopping-cart" /> Total Diskon didapatkan</span>
137
+
138
+          <br />
139
+
140
+          <span class="text-xl font-bold">{{ transactions.totalDiscountGiven }}</span>
141
+        </h2>
142
+      </div>
125 143
     </div>
126 144
     <div class="grid">
127 145
       <div class="col-12">

+ 20
- 4
resources/js/pages/customer/Index.vue 查看文件

@@ -1,7 +1,7 @@
1 1
 <script setup>
2
-import { watch } from 'vue'
2
+import { watch, ref } from 'vue'
3 3
 import { Inertia } from '@inertiajs/inertia'
4
-import { Head, Link, useForm } from '@inertiajs/inertia-vue3'
4
+import { Head, useForm } from '@inertiajs/inertia-vue3'
5 5
 import throttle from 'lodash/throttle'
6 6
 import pickBy from 'lodash/pickBy'
7 7
 import AppButton from '@/components/AppButton.vue'
@@ -23,8 +23,13 @@ watch(
23 23
   filterForm,
24 24
   throttle(() => {
25 25
     Inertia.get('/customers', pickBy({ search: filterForm.search }), { preserveState: true })
26
+
27
+    const params = window.location.search
28
+    exportExcelLink.value = `/reports/customers/export/excel${params}`
26 29
   }, 300)
27 30
 )
31
+
32
+const exportExcelLink = ref('/reports/customers/export/excel')
28 33
 </script>
29 34
 
30 35
 <template>
@@ -43,8 +48,19 @@ watch(
43 48
 
44 49
         <div class="grid">
45 50
           <div class="col-12 md:col-8">
46
-            <div class="flex align-items-center">
47
-              <InputText class="w-full md:w-27rem" placeholder="cari..." v-model="filterForm.search" />
51
+            <div class="grid">
52
+              <div class="col-12 md:col-3">
53
+                <InputText class="w-full" placeholder="cari..." v-model="filterForm.search" />
54
+              </div>
55
+              <div v-if="customers.data" class="col-12 md:col-3">
56
+                <AppButton
57
+                  label="Export excel"
58
+                  class-button="p-button-outlined w-full md:w-16rem"
59
+                  icon="pi pi-file-excel"
60
+                  :inertia-link="false"
61
+                  :href="exportExcelLink"
62
+                />
63
+              </div>
48 64
             </div>
49 65
           </div>
50 66
 

+ 36
- 0
resources/views/excel/customer-report.blade.php 查看文件

@@ -0,0 +1,36 @@
1
+<table>
2
+    <thead>
3
+        <tr>
4
+            <th colspan="7">Detail History Transaksi Customer</th>
5
+        </tr>
6
+        <tr></tr>
7
+        <tr>
8
+            <th>#</th>
9
+            <th>Id Customer</th>
10
+            <th>Nama</th>
11
+            <th>HP</th>
12
+            <th>Total Transaksi</th>
13
+            <th>Total Nilai</th>
14
+            <th>Total Diskon didapat</th>
15
+        </tr>
16
+    </thead>
17
+    <tbody>
18
+        @foreach ($customers->chunk(100) as $chunk)
19
+            @foreach ($chunk as $index => $customer)
20
+                <tr>
21
+                    <td>{{ ++$index }}</td>
22
+                    <td>{{ $customer->customer_number }}</td>
23
+                    <td>{{ $customer->name }}</td>
24
+                    <td>{{ $customer->phone }}</td>
25
+                    <td>{{ $customer->transaction->count() }}</td>
26
+                    <td>
27
+                        {{ (new App\Services\TransactionService())->totalPriceGroupAsString($customer->fresh()->transaction) }}
28
+                    </td>
29
+                    <td>
30
+                        {{ (new App\Services\TransactionService())->totalDiscountGivenGroupAsString($customer->fresh()->transaction) }}
31
+                    </td>
32
+                </tr>
33
+            @endforeach
34
+        @endforeach
35
+    </tbody>
36
+</table>

+ 1
- 0
routes/web.php 查看文件

@@ -35,6 +35,7 @@ Route::middleware(['auth', 'verified'])->group(function () {
35 35
     Route::resource('/users', UserController::class);
36 36
 
37 37
     Route::resource('/customers', CustomerController::class);
38
+    Route::get('/reports/customers/export/excel', [CustomerController::class, 'exportExcel'])->name('customers.excel');
38 39
 
39 40
     Route::resource('/outlets', OutletController::class);
40 41