Przeglądaj źródła

fix: purchase master

rodzic
commit
e3cdc1ee27

+ 2
- 2
app/Http/Controllers/PurchaseController.php Wyświetl plik

@@ -70,7 +70,7 @@ class PurchaseController extends Controller
70 70
             "products" => Inertia::lazy(
71 71
                 fn() => Product::filter(["search" => request("product")])->get()
72 72
             ),
73
-            "historyProductPurchase" => Inertia::lazy(
73
+            "productPurchase" => Inertia::lazy(
74 74
                 fn() => PurchaseDetail::historyProductPurchase(
75 75
                     request()->only("productNumber", "supplierId")
76 76
                 )
@@ -78,7 +78,7 @@ class PurchaseController extends Controller
78 78
                     ->get()
79 79
                     ->transform(
80 80
                         fn($purchaseDetail) => [
81
-                            "id" => $purchaseDetail->id,
81
+                            "number" => $purchaseDetail->product_number,
82 82
                             "price" => $purchaseDetail->price,
83 83
                             "qty" => $purchaseDetail->qty,
84 84
                             "ppn" => $purchaseDetail->purchase->ppn,

+ 7
- 5
app/Models/StockProduct.php Wyświetl plik

@@ -35,11 +35,13 @@ class StockProduct extends Model
35 35
     public function scopeFilter($query, array $filters)
36 36
     {
37 37
         $query->when($filters["search"] ?? null, function ($query, $search) {
38
-            $query->whereHas("product", function ($query) use ($search) {
39
-                $query
40
-                    ->where("number", "like", "%" . $search . "%")
41
-                    ->orWhere("name", "like", "%" . $search . "%");
42
-            });
38
+            $query
39
+                ->whereHas("product", function ($query) use ($search) {
40
+                    $query
41
+                        ->where("number", "like", "%" . $search . "%")
42
+                        ->orWhere("name", "like", "%" . $search . "%");
43
+                })
44
+                ->where("qty", ">", 0);
43 45
         });
44 46
     }
45 47
 }

+ 1
- 0
resources/js/components/AppAutoComplete.vue Wyświetl plik

@@ -67,6 +67,7 @@ const onSelect = (event) => {
67 67
     <label :for="forLabel">{{ label }}</label>
68 68
 
69 69
     <AutoComplete
70
+      forceSelection
70 71
       class="w-full"
71 72
       inputClass="w-full"
72 73
       :model-value="modelValue"

+ 1
- 1
resources/js/pages/Purchases/Components/Cart.vue Wyświetl plik

@@ -1,6 +1,6 @@
1 1
 <script setup>
2 2
 import { ref } from 'vue'
3
-import { IDRCurrencyFormat } from '@/utils/currencyFormat'
3
+import { IDRCurrencyFormat } from '@/utils/helpers'
4 4
 import AppInputNumber from '@/components/AppInputNumber.vue'
5 5
 import AppInputText from '@/components/AppInputText.vue'
6 6
 

+ 1
- 1
resources/js/pages/Purchases/Components/Details.vue Wyświetl plik

@@ -1,5 +1,5 @@
1 1
 <script setup>
2
-import { IDRCurrencyFormat } from '@/utils/currencyFormat'
2
+import { IDRCurrencyFormat } from '@/utils/helpers'
3 3
 
4 4
 defineProps({
5 5
   title: String,

+ 0
- 58
resources/js/pages/Purchases/Components/HistoryProduct.vue Wyświetl plik

@@ -1,58 +0,0 @@
1
-<script setup>
2
-import { watch } from 'vue'
3
-import { Inertia } from '@inertiajs/inertia'
4
-import { usePage } from '@inertiajs/inertia-vue3'
5
-import AppInputNumber from '@/components/AppInputNumber.vue'
6
-import AppInputText from '@/components/AppInputText.vue'
7
-
8
-const props = defineProps(['product', 'supplier'])
9
-
10
-watch(
11
-  () => props.product,
12
-  () => {
13
-    if (props.product?.number && props.supplier?.id) {
14
-      Inertia.reload({
15
-        data: {
16
-          productNumber: props.product.number,
17
-          supplierId: props.supplier.id,
18
-        },
19
-        only: ['historyProductPurchase'],
20
-      })
21
-    }
22
-
23
-    usePage().props.value.historyProductPurchase = {}
24
-  }
25
-)
26
-</script>
27
-
28
-<template>
29
-  <template v-if="$page.props.historyProductPurchase?.id">
30
-    <div class="col-12">
31
-      <h3 class="text-lg">Riwayat Produk Sebelumnya</h3>
32
-    </div>
33
-
34
-    <div class="col-12 md:col-6">
35
-      <AppInputNumber
36
-        disabled
37
-        class="mb-0"
38
-        label="Harga "
39
-        placeholder="harga"
40
-        v-model="$page.props.historyProductPurchase.price"
41
-      />
42
-
43
-      <span v-if="$page.props.historyProductPurchase.ppn" class="text-xs">
44
-        Harga sudah termasuk PPN {{ $page.props.ppn }} %
45
-      </span>
46
-    </div>
47
-
48
-    <div class="col-12 md:col-6">
49
-      <AppInputText
50
-        disabled
51
-        label="Kuantitas"
52
-        placeholder="kuantitas"
53
-        type="number"
54
-        v-model="$page.props.historyProductPurchase.qty"
55
-      />
56
-    </div>
57
-  </template>
58
-</template>

resources/js/pages/Purchases/Composables/onShowDialog.js → resources/js/pages/Purchases/Composables/useDialog.js Wyświetl plik

@@ -1,9 +1,9 @@
1
-import { useDialog } from 'primevue/usedialog'
1
+import { useDialog as usePrimeDialog } from 'primevue/usedialog'
2 2
 import SupplierCreate from '../Components/SupplierCreate.vue'
3 3
 import ProductCreate from '../Components/ProductCreate.vue'
4 4
 
5
-export function onShowDialog() {
6
-  const dialog = useDialog()
5
+export function useDialog() {
6
+  const dialog = usePrimeDialog()
7 7
 
8 8
   const dialogStyle = {
9 9
     style: {

+ 25
- 7
resources/js/pages/Purchases/Composables/useProductCart.js Wyświetl plik

@@ -1,24 +1,35 @@
1 1
 import { reactive } from 'vue'
2
-import FormValidationError from '@/utils/FormValidationError'
2
+import { FormValidationError } from '@/utils/helpers'
3 3
 
4 4
 export function useProductCart(form, initialProducts = []) {
5 5
   const productCart = reactive(initialProducts)
6 6
 
7 7
   const productCartDeleted = reactive([])
8 8
 
9
+  const productErrors = reactive([])
10
+
9 11
   const productValidation = () => {
10
-    const existProduct = productCart.find(
12
+    onClearProductErrors()
13
+
14
+    const productExists = productCart.find(
11 15
       (product) => product.number === form.product.number
12 16
     )
13 17
 
14
-    if (existProduct) {
15
-      throw new FormValidationError('Produk sudah ada dikeranjang', 'product')
18
+    if (productExists) {
19
+      productErrors.push({
20
+        message: 'Produk sudah ada dikeranjang',
21
+        field: 'product',
22
+      })
23
+    }
24
+
25
+    if (productErrors.length) {
26
+      throw new FormValidationError('form error', productErrors)
16 27
     }
17 28
   }
18 29
 
19 30
   const onAddProduct = () => {
20 31
     try {
21
-      form.clearErrors('product', 'price', 'qty')
32
+      form.clearErrors('product', 'qty')
22 33
 
23 34
       productValidation()
24 35
 
@@ -27,13 +38,15 @@ export function useProductCart(form, initialProducts = []) {
27 38
         number: form.product.number,
28 39
         name: form.product.name,
29 40
         price: form.price,
30
-        qty: form.qty,
41
+        qty: Number(form.qty),
31 42
         unit: form.product.unit,
32 43
       })
33 44
 
34 45
       form.reset('product', 'price', 'qty')
35 46
     } catch (e) {
36
-      form.setError(e.field, e.message)
47
+      e.errors.forEach((error) => {
48
+        form.setError(error.field, error.message)
49
+      })
37 50
     }
38 51
   }
39 52
 
@@ -56,6 +69,10 @@ export function useProductCart(form, initialProducts = []) {
56 69
     productCartDeleted.splice(0)
57 70
   }
58 71
 
72
+  const onClearProductErrors = () => {
73
+    productErrors.splice(0)
74
+  }
75
+
59 76
   const totalProductPrice = () => {
60 77
     const productPrices = productCart.map((product) => {
61 78
       if (form.checkedPpn) {
@@ -80,6 +97,7 @@ export function useProductCart(form, initialProducts = []) {
80 97
   return {
81 98
     productCart,
82 99
     productCartDeleted,
100
+    productErrors,
83 101
     onClearProductCart,
84 102
     onClearProductCartDelete,
85 103
     onAddProduct,

+ 79
- 17
resources/js/pages/Purchases/Create.vue Wyświetl plik

@@ -1,12 +1,14 @@
1 1
 <script setup>
2
-import { computed } from 'vue'
2
+import { computed, watch, watchEffect } from 'vue'
3
+import { Inertia } from '@inertiajs/inertia'
4
+import { once } from 'lodash'
5
+import { ppn } from '@/utils/helpers'
3 6
 import { optionStatus } from './config'
4 7
 import { cartTable } from './config'
5 8
 import Details from './Components/Details.vue'
6 9
 import Cart from './Components/Cart.vue'
7
-import HistoryProduct from './Components/HistoryProduct.vue'
8 10
 import { useProductCart } from './Composables/useProductCart'
9
-import { onShowDialog } from './Composables/onShowDialog'
11
+import { useDialog } from './Composables/useDialog'
10 12
 import { useForm } from '@/composables/useForm'
11 13
 import AppInputText from '@/components/AppInputText.vue'
12 14
 import AppInputNumber from '@/components/AppInputNumber.vue'
@@ -25,7 +27,7 @@ const props = defineProps({
25 27
     type: Array,
26 28
     default: [],
27 29
   },
28
-  historyProductPurchase: Object,
30
+  productPurchase: Object,
29 31
 })
30 32
 
31 33
 const form = useForm({
@@ -56,20 +58,53 @@ const onSubmit = () => {
56 58
     })
57 59
 }
58 60
 
61
+watchEffect(() => {
62
+  if (props.productPurchase?.number) {
63
+    form.price = props.productPurchase.price
64
+
65
+    form.qty = props.productPurchase.qty
66
+  } else {
67
+    form.price = null
68
+  }
69
+})
70
+
71
+watch(
72
+  () => form.product,
73
+  () => {
74
+    if (form.product?.number) {
75
+      Inertia.reload({
76
+        data: {
77
+          productNumber: form.product.number,
78
+          supplierId: form.supplier.id,
79
+        },
80
+        only: ['productPurchase'],
81
+      })
82
+    }
83
+  }
84
+)
85
+
86
+const productUnit = computed(() => form.product?.unit)
87
+
88
+const productPurchasePrice = computed(() => props.productPurchase?.price)
89
+
90
+const productPurchasePpn = computed(() => props.productPurchase?.ppn)
91
+
92
+const productPurchaseQty = computed(() => props.productPurchase?.qty)
93
+
59 94
 const dropdownStatus = computed(() => {
60 95
   return optionStatus.filter((val) => val.value != 'success')
61 96
 })
62 97
 
63 98
 const {
64 99
   productCart,
100
+  productErrors,
65 101
   onClearProductCart,
66 102
   onAddProduct,
67 103
   onDeleteProduct,
68
-  onEditProduct,
69 104
   totalProductPrice,
70 105
 } = useProductCart(form)
71 106
 
72
-const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
107
+const { onShowCreateProduct, onShowCreateSupplier } = useDialog()
73 108
 </script>
74 109
 
75 110
 <template>
@@ -144,7 +179,7 @@ const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
144 179
                       field="name"
145 180
                       refresh-data="products"
146 181
                       v-model="form.product"
147
-                      :error="form.errors.products"
182
+                      :error="form.errors.product"
148 183
                       :suggestions="products"
149 184
                     >
150 185
                       <template #item="slotProps">
@@ -168,27 +203,50 @@ const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
168 203
                     </AppAutoComplete>
169 204
                   </div>
170 205
 
171
-                  <div v-if="form.product?.number" class="col-12 md:col-6">
206
+                  <div class="col-12 md:col-6">
172 207
                     <AppInputText
173 208
                       disabled
174 209
                       label="Satuan"
175 210
                       placeholder="satuan"
176
-                      v-model="form.product.unit"
211
+                      v-model="productUnit"
177 212
                     />
178 213
                   </div>
179 214
 
180 215
                   <Divider type="dashed" />
181 216
 
182
-                  <HistoryProduct
183
-                    :product="form.product"
184
-                    :supplier="form.supplier"
185
-                  />
217
+                  <div class="col-12">
218
+                    <h3 class="text-lg">Riwayat Produk Sebelumnya</h3>
219
+                  </div>
220
+
221
+                  <div class="col-12 md:col-6">
222
+                    <AppInputNumber
223
+                      disabled
224
+                      class="mb-0"
225
+                      label="Harga "
226
+                      placeholder="harga"
227
+                      v-model="productPurchasePrice"
228
+                    />
229
+
230
+                    <span v-if="productPurchasePpn" class="text-xs">
231
+                      Harga sudah termasuk PPN {{ ppn }} %
232
+                    </span>
233
+                  </div>
234
+
235
+                  <div class="col-12 md:col-6">
236
+                    <AppInputText
237
+                      disabled
238
+                      label="Kuantitas"
239
+                      placeholder="kuantitas"
240
+                      type="number"
241
+                      v-model="productPurchaseQty"
242
+                    />
243
+                  </div>
186 244
 
187 245
                   <Divider type="dashed" />
188 246
 
189 247
                   <div class="col-12 md:col-6">
190 248
                     <AppInputNumber
191
-                      :disabled="!form.supplier?.id"
249
+                      :disabled="!form.product?.id"
192 250
                       label="Harga Terbaru"
193 251
                       placeholder="harga terbaru"
194 252
                       v-model="form.price"
@@ -197,7 +255,7 @@ const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
197 255
 
198 256
                   <div class="col-12 md:col-6">
199 257
                     <AppInputText
200
-                      :disabled="!form.supplier?.id"
258
+                      :disabled="!form.product?.id"
201 259
                       label="Kuantitas"
202 260
                       placeholder="kuantitas"
203 261
                       type="number"
@@ -212,8 +270,12 @@ const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
212 270
                     label="Tambah Produk"
213 271
                     icon="pi pi-check"
214 272
                     class="p-button-outlined"
273
+                    :class="{ 'p-button-danger': productErrors.length }"
215 274
                     :disabled="
216
-                      !form.price || !form.qty || !form.product?.number
275
+                      !form.price ||
276
+                      !Number(form.qty) ||
277
+                      !form.product?.number ||
278
+                      productErrors.length
217 279
                     "
218 280
                     @click="onAddProduct"
219 281
                   />
@@ -227,9 +289,9 @@ const { onShowCreateProduct, onShowCreateSupplier } = onShowDialog()
227 289
               title="Keranjang Produk"
228 290
               :product-cart="productCart"
229 291
               :header-table="cartTable"
292
+              :btn-edit-show="false"
230 293
               v-model:checked-ppn="form.checkedPpn"
231 294
               @delete="onDeleteProduct"
232
-              @edit="onEditProduct"
233 295
             />
234 296
           </div>
235 297
         </div>

+ 1
- 1
resources/js/pages/Purchases/Show.vue Wyświetl plik

@@ -1,6 +1,6 @@
1 1
 <script setup>
2 2
 import { useForm } from '@/composables/useForm'
3
-import { IDRCurrencyFormat } from '@/utils/currencyFormat'
3
+import { IDRCurrencyFormat } from '@/utils/helpers'
4 4
 import { cartTable } from './config'
5 5
 import Cart from './Components/Cart.vue'
6 6
 import { useProductCart } from './Composables/useProductCart'

+ 0
- 10
resources/js/pages/Sales/Composables/useProductCart.js Wyświetl plik

@@ -96,15 +96,6 @@ export function useProductCart(form, initialProducts = []) {
96 96
     )
97 97
   }
98 98
 
99
-  const onEditProduct = (event) => {
100
-    const { newData, index } = event
101
-
102
-    productCart[index] = {
103
-      ...newData,
104
-      label: 'edit',
105
-    }
106
-  }
107
-
108 99
   return {
109 100
     productCart,
110 101
     productCartDeleted,
@@ -113,7 +104,6 @@ export function useProductCart(form, initialProducts = []) {
113 104
     onClearProductCartDelete,
114 105
     onAddProduct,
115 106
     onDeleteProduct,
116
-    onEditProduct,
117 107
     totalProductPrice,
118 108
   }
119 109
 }

+ 1
- 1
resources/js/pages/Sales/Show.vue Wyświetl plik

@@ -1,6 +1,6 @@
1 1
 <script setup>
2 2
 import { useForm } from '@/composables/useForm'
3
-import { IDRCurrencyFormat } from '@/utils/currencyFormat'
3
+import { IDRCurrencyFormat } from '@/utils/helpers'
4 4
 import { cartTable } from './config'
5 5
 import Cart from './Components/Cart.vue'
6 6
 import { useProductCart } from './Composables/useProductCart'