Bläddra i källkod

fix: purchase master

Muhammad Iqbal Afandi 3 år sedan
förälder
incheckning
a287517a10

+ 1
- 1
app/Http/Controllers/PurchaseController.php Visa fil

@@ -56,7 +56,7 @@ class PurchaseController extends Controller
56 56
     {
57 57
         return inertia('Purchases/Create', [
58 58
             'number' => 'PBN' . now()->format('YmdHis'),
59
-            'ppn' => Ppn::first()->ppn,
59
+            'ppn' => Ppn::first()->getRawOriginal('ppn'),
60 60
             'productNumber' => Inertia::lazy(
61 61
                 fn() => 'PDK' . now()->format('YmdHis')
62 62
             ),

+ 1
- 1
database/migrations/2022_06_16_091344_create_products_table.php Visa fil

@@ -18,7 +18,7 @@ return new class extends Migration
18 18
             $table->string('number')->unique();
19 19
             $table->string('name');
20 20
             $table->string('unit');
21
-            $table->unsignedTinyInteger('profit');
21
+            $table->unsignedTinyInteger('profit')->default(0);
22 22
             $table->timestamps();
23 23
         });
24 24
     }

resources/js/assets/styles/sass/global.scss → resources/css/app.scss Visa fil

@@ -105,11 +105,3 @@ p {
105 105
   padding: 0.25em 0.5rem;
106 106
   max-width: 12.5rem;
107 107
 }
108
-
109
-.p-message {
110
-  margin-top: 0px;
111
-}
112
-
113
-.p-component-overlay {
114
-  z-index: 997;
115
-}

+ 45
- 0
resources/js/pages/Purchases/Components/Cart.vue Visa fil

@@ -0,0 +1,45 @@
1
+<script setup>
2
+defineProps({
3
+  title: String,
4
+  headerTable: {
5
+    required: true,
6
+    type: Array,
7
+  },
8
+  value: {
9
+    required: true,
10
+    type: Array,
11
+  },
12
+})
13
+</script>
14
+
15
+<template>
16
+  <DataTable
17
+    responsiveLayout="scroll"
18
+    columnResizeMode="expand"
19
+    :value="value"
20
+    :rowHover="true"
21
+    :stripedRows="true"
22
+  >
23
+    <template #header>
24
+      <h2 class="text-2xl font-bold">{{ title }}</h2>
25
+    </template>
26
+
27
+    <Column
28
+      v-for="value in headerTable"
29
+      :field="value.field"
30
+      :header="value.header"
31
+      :key="value.field"
32
+    />
33
+
34
+    <Column>
35
+      <template #body="{ index }">
36
+        <Button
37
+          icon="pi pi-trash"
38
+          class="p-button-icon-only p-button-rounded p-button-text"
39
+          v-tooltip.bottom="'hapus'"
40
+          @click="$emit('delete', index)"
41
+        />
42
+      </template>
43
+    </Column>
44
+  </DataTable>
45
+</template>

+ 24
- 38
resources/js/pages/Purchases/Components/Details.vue Visa fil

@@ -1,16 +1,16 @@
1 1
 <script setup>
2 2
 import { IDRCurrencyFormat } from '@/utils/currencyFormat'
3 3
 
4
-defineProps([
5
-  'title',
6
-  'number',
7
-  'price',
8
-  'qty',
9
-  'ppn',
10
-  'status',
11
-  'person',
12
-  'product',
13
-])
4
+defineProps({
5
+  title: String,
6
+  number: String,
7
+  price: Number,
8
+  qty: String,
9
+  ppn: Number,
10
+  status: String,
11
+  person: Object,
12
+  disabled: Boolean,
13
+})
14 14
 </script>
15 15
 
16 16
 <template>
@@ -67,38 +67,12 @@ defineProps([
67 67
           </div>
68 68
         </div>
69 69
 
70
-        <div class="col-12">
71
-          <div
72
-            v-if="
73
-              product !== null &&
74
-              typeof product === 'object' &&
75
-              Object.keys(product).length
76
-            "
77
-            class="grid"
78
-          >
79
-            <div class="col">
80
-              <h3 class="text-base">Nomor Produk</h3>
81
-              <span>{{ product.number }}</span>
82
-            </div>
83
-
84
-            <div class="col">
85
-              <h3 class="text-base">Nama Produk</h3>
86
-              <span>{{ product.name }}</span>
87
-            </div>
88
-
89
-            <div class="col">
90
-              <h3 class="text-base">Satuan</h3>
91
-              <span>{{ product.unit }}</span>
92
-            </div>
93
-          </div>
94
-        </div>
95
-
96 70
         <Divider type="dashed" />
97 71
         <div class="col-12">
98 72
           <div class="grid">
99 73
             <div class="col">
100 74
               <h3 class="text-base">Harga</h3>
101
-              <span>{{ IDRCurrencyFormat(price) }}</span>
75
+              <span v-if="price">{{ IDRCurrencyFormat(price) }}</span>
102 76
             </div>
103 77
 
104 78
             <div class="col">
@@ -108,11 +82,23 @@ defineProps([
108 82
 
109 83
             <div class="col">
110 84
               <h3 class="text-base">PPN</h3>
111
-              <span>{{ ppn }}</span>
85
+              <span>{{ ppn }} %</span>
112 86
             </div>
113 87
           </div>
114 88
         </div>
115 89
       </div>
116 90
     </template>
91
+
92
+    <template #footer>
93
+      <div class="flex flex-column md:flex-row justify-content-end">
94
+        <Button
95
+          label="Simpan"
96
+          icon="pi pi-check"
97
+          class="p-button-outlined"
98
+          :disabled="disabled"
99
+          @click="$emit('click')"
100
+        />
101
+      </div>
102
+    </template>
117 103
   </Card>
118 104
 </template>

resources/js/pages/Purchases/Components/Dialog/ProductCreate.vue → resources/js/pages/Purchases/Components/ProductCreate.vue Visa fil


resources/js/pages/Purchases/Components/Dialog/SupplierCreate.vue → resources/js/pages/Purchases/Components/SupplierCreate.vue Visa fil


+ 46
- 0
resources/js/pages/Purchases/Composables/useProductCart.js Visa fil

@@ -0,0 +1,46 @@
1
+import { reactive } from 'vue'
2
+import FormValidationError from '@/utils/FormValidationError'
3
+
4
+export function useProductCart(form) {
5
+  const cartProduct = reactive([])
6
+
7
+  const productAddValidation = () => {
8
+    if (form.price) {
9
+      throw new FormValidationError('Nilai tidak boleh kosong', 'price')
10
+    } else if (form.qty) {
11
+      throw new FormValidationError('Nilai tidak boleh kosong', 'qty')
12
+    } else if (form.product) {
13
+      throw new FormValidationError('Nilai tidak boleh kosong', 'product')
14
+    }
15
+  }
16
+
17
+  const onAddProduct = () => {
18
+    try {
19
+      form.clearErrors(['price', 'qty', 'product'])
20
+
21
+      productAddValidation()
22
+
23
+      cartProduct.push({
24
+        number: form.product.number,
25
+        name: form.product.name,
26
+        price: form.price,
27
+        qty: form.qty,
28
+      })
29
+    } catch (e) {
30
+      form.setError(e.field, e.message)
31
+    }
32
+  }
33
+
34
+  const onDeleteProduct = (index) => {
35
+    cartProduct.splice(index)
36
+  }
37
+
38
+  const onClearProduct = () => {}
39
+
40
+  return {
41
+    cartProduct,
42
+    onAddProduct,
43
+    onDeleteProduct,
44
+    onClearProduct,
45
+  }
46
+}

+ 47
- 31
resources/js/pages/Purchases/Create.vue Visa fil

@@ -1,9 +1,12 @@
1 1
 <script setup>
2 2
 import { useDialog } from 'primevue/usedialog'
3 3
 import { optionStatus, dialogStyle } from './config'
4
-import SupplierCreate from './Components/Dialog/SupplierCreate.vue'
5
-import ProductCreate from './Components/Dialog/ProductCreate.vue'
4
+import { cartTable } from './config'
5
+import SupplierCreate from './Components/SupplierCreate.vue'
6
+import ProductCreate from './Components/ProductCreate.vue'
6 7
 import Details from './Components/Details.vue'
8
+import Cart from './Components/Cart.vue'
9
+import { useProductCart } from './Composables/useProductCart'
7 10
 import { useForm } from '@/composables/useForm'
8 11
 import AppInputText from '@/components/AppInputText.vue'
9 12
 import AppInputNumber from '@/components/AppInputNumber.vue'
@@ -13,7 +16,7 @@ import DashboardLayout from '@/layouts/Dashboard/DashboardLayout.vue'
13 16
 
14 17
 const props = defineProps({
15 18
   number: String,
16
-  ppn: String,
19
+  ppn: Number,
17 20
   suppliers: {
18 21
     type: Array,
19 22
     default: [],
@@ -48,9 +51,12 @@ const onSubmit = () => {
48 51
     })
49 52
 }
50 53
 
54
+const { cartProduct, onAddProduct, onDeleteProduct, onClearProduct } =
55
+  useProductCart(form)
56
+
51 57
 const dialog = useDialog()
52 58
 
53
-const showCreateSupplier = () => {
59
+const onShowCreateSupplier = () => {
54 60
   dialog.open(SupplierCreate, {
55 61
     props: {
56 62
       header: 'Tambah Supplier',
@@ -59,7 +65,7 @@ const showCreateSupplier = () => {
59 65
   })
60 66
 }
61 67
 
62
-const showCreateProduct = () => {
68
+const onShowCreateProduct = () => {
63 69
   dialog.open(ProductCreate, {
64 70
     props: {
65 71
       header: 'Tambah Produk',
@@ -67,14 +73,6 @@ const showCreateProduct = () => {
67 73
     },
68 74
   })
69 75
 }
70
-
71
-const checkBtnSubmit = () => {
72
-  if (form.price && form.qty && form.supplier && form.product) {
73
-    return false
74
-  } else {
75
-    return true
76
-  }
77
-}
78 76
 </script>
79 77
 
80 78
 <template>
@@ -82,9 +80,9 @@ const checkBtnSubmit = () => {
82 80
     <DynamicDialog />
83 81
 
84 82
     <div class="grid">
85
-      <div class="col-12 lg:col-8">
83
+      <div class="col-12 md:col-8 flex-order-1 md:flex-order-0">
86 84
         <Card>
87
-          <template #title> Tambah Pembelian </template>
85
+          <template #title> Pembeli </template>
88 86
           <template #content>
89 87
             <div class="grid">
90 88
               <div class="col-12 md:col-6">
@@ -130,14 +128,36 @@ const checkBtnSubmit = () => {
130 128
                     <span
131 129
                       class="cursor-pointer"
132 130
                       style="color: var(--primary-color)"
133
-                      @click="showCreateSupplier"
131
+                      @click="onShowCreateSupplier"
134 132
                     >
135 133
                       Tambah Supplier
136 134
                     </span>
137 135
                   </template>
138 136
                 </AppAutoComplete>
139 137
               </div>
138
+            </div>
139
+          </template>
140
+        </Card>
141
+      </div>
142
+
143
+      <div class="col-12 md:col-4 flex-order-4 md:flex-order-0">
144
+        <Details
145
+          title="Detail Pembelian"
146
+          :number="number"
147
+          :ppn="ppn"
148
+          :status="form.status"
149
+          :person="form.supplier"
150
+          :product="form.product"
151
+          :disabled="form.processing"
152
+          @click="onSubmit"
153
+        />
154
+      </div>
140 155
 
156
+      <div class="col-12 md:col-8 flex-order-2 md:flex-order-0">
157
+        <Card>
158
+          <template #title>Produk</template>
159
+          <template #content>
160
+            <div class="grid">
141 161
               <div class="col-12 md:col-6">
142 162
                 <AppAutoComplete
143 163
                   label="Produk"
@@ -161,7 +181,7 @@ const checkBtnSubmit = () => {
161 181
                     <span
162 182
                       class="cursor-pointer"
163 183
                       style="color: var(--primary-color)"
164
-                      @click="showCreateProduct"
184
+                      @click="onShowCreateProduct"
165 185
                     >
166 186
                       Tambah Produk
167 187
                     </span>
@@ -189,31 +209,27 @@ const checkBtnSubmit = () => {
189 209
               </div>
190 210
             </div>
191 211
           </template>
192
-
193 212
           <template #footer>
194 213
             <div class="flex flex-column md:flex-row justify-content-end">
195 214
               <Button
196
-                label="Simpan"
215
+                label="Tambah Produk"
197 216
                 icon="pi pi-check"
198 217
                 class="p-button-outlined"
199
-                :disabled="form.processing || checkBtnSubmit()"
200
-                @click="onSubmit"
218
+                :disabled="form.processing"
219
+                @click="onAddProduct"
201 220
               />
202 221
             </div>
203 222
           </template>
204 223
         </Card>
205 224
       </div>
206 225
 
207
-      <div class="col-12 lg:col-4">
208
-        <Details
209
-          title="Detail Pembelian"
210
-          :number="number"
211
-          :price="form.price"
212
-          :qty="form.qty"
213
-          :ppn="ppn"
214
-          :status="form.status"
215
-          :person="form.supplier"
216
-          :product="form.product"
226
+      <div class="col-12 md:col-8 flex-order-3 md:flex-order-0">
227
+        <Cart
228
+          title="Keranjang Produk"
229
+          :header-table="cartTable"
230
+          :form="form"
231
+          :value="cartProduct"
232
+          @delete="onDeleteProduct"
217 233
         />
218 234
       </div>
219 235
     </div>

+ 7
- 0
resources/js/pages/Purchases/config.js Visa fil

@@ -20,6 +20,13 @@ export const indexTable = [
20 20
   { field: 'productNumber', header: 'Nomor Produk' },
21 21
 ]
22 22
 
23
+export const cartTable = [
24
+  { field: 'number', header: 'Nomor Produk' },
25
+  { field: 'name', header: 'Produk' },
26
+  { field: 'price', header: 'Harga' },
27
+  { field: 'quantity', header: 'Kuantitas' },
28
+]
29
+
23 30
 export const dialogStyle = {
24 31
   style: {
25 32
     width: '50vw',

+ 10
- 8
resources/js/vue.js Visa fil

@@ -1,4 +1,5 @@
1 1
 import './bootstrap'
2
+import '../css/app.scss'
2 3
 import { createApp, h } from 'vue'
3 4
 import { createInertiaApp } from '@inertiajs/inertia-vue3'
4 5
 import { InertiaProgress } from '@inertiajs/progress'
@@ -8,7 +9,6 @@ import 'primevue/resources/themes/mdc-light-indigo/theme.css'
8 9
 import 'primevue/resources/primevue.min.css'
9 10
 import 'primeflex/primeflex.css'
10 11
 import 'primeicons/primeicons.css'
11
-import '@/assets/styles/sass/global.scss'
12 12
 import PrimeVue from 'primevue/config'
13 13
 import StyleClass from 'primevue/styleclass'
14 14
 import AutoComplete from 'primevue/autocomplete'
@@ -29,12 +29,9 @@ import Editor from 'primevue/editor'
29 29
 import InputNumber from 'primevue/inputnumber'
30 30
 import InputText from 'primevue/inputtext'
31 31
 import Message from 'primevue/message'
32
-import Paginator from 'primevue/paginator'
33 32
 import Password from 'primevue/password'
34
-import Ripple from 'primevue/ripple'
35 33
 import TabView from 'primevue/tabview'
36 34
 import TabPanel from 'primevue/tabpanel'
37
-import Textarea from 'primevue/textarea'
38 35
 import Tooltip from 'primevue/tooltip'
39 36
 
40 37
 createInertiaApp({
@@ -47,12 +44,19 @@ createInertiaApp({
47 44
   setup({ el, App, props, plugin }) {
48 45
     createApp({ render: () => h(App, props) })
49 46
       .use(plugin)
50
-      .use(PrimeVue, { ripple: true })
47
+      .use(PrimeVue, {
48
+        ripple: true,
49
+        zIndex: {
50
+          modal: 1100,
51
+          overlay: 1000,
52
+          menu: 1000,
53
+          tooltip: 1100,
54
+        },
55
+      })
51 56
       .use(ConfirmationService)
52 57
       .use(DialogService)
53 58
       .mixin({ methods: { route } })
54 59
       .directive('styleclass', StyleClass)
55
-      .directive('ripple', Ripple)
56 60
       .directive('tooltip', Tooltip)
57 61
       .component('AutoComplete', AutoComplete)
58 62
       .component('Button', Button)
@@ -70,11 +74,9 @@ createInertiaApp({
70 74
       .component('InputNumber', InputNumber)
71 75
       .component('InputText', InputText)
72 76
       .component('Message', Message)
73
-      .component('Paginator', Paginator)
74 77
       .component('Password', Password)
75 78
       .component('TabView', TabView)
76 79
       .component('TabPanel', TabPanel)
77
-      .component('Textarea', Textarea)
78 80
       .mount(el)
79 81
   },
80 82
 })