123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <script setup>
  2. import { computed, watchEffect } from 'vue'
  3. import { profit } from '@/utils/helpers'
  4. import { optionStatus } from './config'
  5. import { cartTable } from './config'
  6. import Details from './Components/Details.vue'
  7. import Cart from './Components/Cart.vue'
  8. import { useCart } from './Composables/useCart'
  9. import { useDialog } from './Composables/useDialog'
  10. import { useForm } from '@/composables/useForm'
  11. import AppInputText from '@/components/AppInputText.vue'
  12. import AppInputNumber from '@/components/AppInputNumber.vue'
  13. import AppDropdown from '@/components/AppDropdown.vue'
  14. import AppAutoComplete from '@/components/AppAutoComplete.vue'
  15. import DashboardLayout from '@/layouts/Dashboard/DashboardLayout.vue'
  16. const props = defineProps({
  17. number: String,
  18. ppn: Number,
  19. customers: {
  20. type: Array,
  21. default: [],
  22. },
  23. stockProducts: {
  24. type: Array,
  25. default: [],
  26. },
  27. })
  28. const form = useForm({
  29. status: 'success',
  30. price: null,
  31. qty: null,
  32. customer: null,
  33. product: null,
  34. ppn: props.ppn,
  35. checkedPpn: false,
  36. })
  37. const onSubmit = () => {
  38. form
  39. .transform((data) => ({
  40. number: props.number,
  41. status: data.status,
  42. ppn: data.checkedPpn,
  43. customer_id: data.customer.id,
  44. products: cart,
  45. }))
  46. .post(route('sales.store'), {
  47. onSuccess: () => {
  48. form.reset()
  49. onClearCart()
  50. },
  51. })
  52. }
  53. watchEffect(() => {
  54. if (form.product?.number) {
  55. form.price = profit(form.product.price, form.product.profit)
  56. form.qty = 1
  57. }
  58. })
  59. const dropdownStatus = computed(() => {
  60. return optionStatus.filter((val) => val.value != 'pending')
  61. })
  62. const productProductUnit = computed(() => form.product?.unit)
  63. const productProductPrice = computed(() => form.product?.price)
  64. const productProductPpn = computed(() => form.product?.ppn)
  65. const productProductQty = computed(() => form.product?.qty)
  66. const profitDescription = computed(() => {
  67. const priceProfit = profit(form.product?.price, form.product?.profit)
  68. return form.price === priceProfit ? true : false
  69. })
  70. const {
  71. cart,
  72. cartErrors,
  73. onAddCart,
  74. onClearCart,
  75. onDeleteCart,
  76. totalCartPrice,
  77. } = useCart(form)
  78. const { onShowCustomerCreate } = useDialog()
  79. </script>
  80. <template>
  81. <DashboardLayout title="Tambah Penjualan">
  82. <DynamicDialog />
  83. <div class="grid">
  84. <div class="col-12 md:col-8">
  85. <div class="grid">
  86. <div class="col-12">
  87. <Card>
  88. <template #title> Transaksi </template>
  89. <template #content>
  90. <div class="grid">
  91. <div class="col-12 md:col-6">
  92. <AppDropdown
  93. label="Status"
  94. placeholder="status"
  95. :options="dropdownStatus"
  96. :error="form.errors.status"
  97. v-model="form.status"
  98. />
  99. </div>
  100. <div class="col-12 md:col-6">
  101. <AppAutoComplete
  102. empty
  103. label="Pelanggan"
  104. placeholder="pelanggan"
  105. field="name"
  106. refresh-data="customers"
  107. v-model="form.customer"
  108. :error="form.errors.customer_id"
  109. :suggestions="customers"
  110. >
  111. <template #item="slotProps">
  112. <template v-if="slotProps.item">
  113. <div class="flex flex-column">
  114. <span>{{ slotProps.item.name }}</span>
  115. <span>{{ slotProps.item.phone }}</span>
  116. </div>
  117. </template>
  118. </template>
  119. <template #empty>
  120. <span
  121. class="cursor-pointer"
  122. style="color: var(--primary-color)"
  123. @click="onShowCustomerCreate"
  124. >
  125. Tambah Pelanggan
  126. </span>
  127. </template>
  128. </AppAutoComplete>
  129. </div>
  130. </div>
  131. </template>
  132. </Card>
  133. </div>
  134. <div class="col-12">
  135. <Card>
  136. <template #title>Produk</template>
  137. <template #content>
  138. <div class="grid">
  139. <div class="col-12 md:col-6">
  140. <AppAutoComplete
  141. :disabled="!form.customer?.id"
  142. empty
  143. label="Produk"
  144. placeholder="produk"
  145. field="name"
  146. refresh-data="stockProducts"
  147. v-model="form.product"
  148. :error="form.errors.product"
  149. :suggestions="stockProducts"
  150. >
  151. <template #item="slotProps">
  152. <template v-if="slotProps.item">
  153. <div class="flex flex-column">
  154. <span>{{ slotProps.item.number }}</span>
  155. <span>{{ slotProps.item.name }}</span>
  156. </div>
  157. </template>
  158. </template>
  159. </AppAutoComplete>
  160. </div>
  161. <Divider type="dashed" />
  162. <div class="col-12">
  163. <h3 class="text-lg">Riwayat Pembelian Sebelumnya</h3>
  164. </div>
  165. <div class="col-12 md:col-6">
  166. <AppInputText
  167. disabled
  168. label="Satuan"
  169. placeholder="satuan"
  170. v-model="productProductUnit"
  171. />
  172. </div>
  173. <div class="col-12 md:col-6">
  174. <AppInputNumber
  175. disabled
  176. class="mb-0"
  177. label="Harga"
  178. placeholder="harga"
  179. v-model="productProductPrice"
  180. />
  181. <span v-if="productProductPpn" class="text-xs">
  182. Harga sudah termasuk PPN {{ ppn }} %
  183. </span>
  184. </div>
  185. <div class="col-12 md:col-6">
  186. <AppInputText
  187. disabled
  188. label="Stok Tersedia"
  189. placeholder="stok tersedia"
  190. type="number"
  191. v-model="productProductQty"
  192. />
  193. </div>
  194. <Divider type="dashed" />
  195. <div class="col-12 md:col-6">
  196. <AppInputNumber
  197. class="m-0"
  198. :disabled="!form.product?.number"
  199. label="Harga Jual"
  200. placeholder="harga jual"
  201. v-model="form.price"
  202. />
  203. <span v-if="profitDescription" class="text-xs">
  204. Sudah termasuk profit {{ form.product.profit }} %
  205. </span>
  206. </div>
  207. <div class="col-12 md:col-6">
  208. <AppInputText
  209. :disabled="!form.product?.number"
  210. label="Kuantitas"
  211. placeholder="kuantitas"
  212. type="number"
  213. :error="form.errors.qty"
  214. v-model="form.qty"
  215. />
  216. </div>
  217. </div>
  218. </template>
  219. <template #footer>
  220. <div class="flex flex-column md:flex-row justify-content-end">
  221. <Button
  222. label="Tambah Produk"
  223. icon="pi pi-check"
  224. class="p-button-outlined"
  225. :class="{ 'p-button-danger': cartErrors.length }"
  226. :disabled="
  227. !form.price || form.qty <= 0 || !form.product?.number
  228. "
  229. @click="onAddCart"
  230. />
  231. </div>
  232. </template>
  233. </Card>
  234. </div>
  235. <div class="col-12">
  236. <Cart
  237. title="Keranjang Produk"
  238. :cart="cart"
  239. :header-table="cartTable"
  240. :btn-edit-show="false"
  241. v-model:checked-ppn="form.checkedPpn"
  242. @delete="onDeleteCart"
  243. />
  244. </div>
  245. </div>
  246. </div>
  247. <div class="col-12 md:col-4">
  248. <Details
  249. title="Detail Penjualan"
  250. message="Pastikan semua produk sudah benar"
  251. :number="number"
  252. :status="form.status"
  253. :person="form.customer"
  254. :product="form.product"
  255. :price="totalCartPrice()"
  256. :disabled="
  257. form.processing ||
  258. !form.status ||
  259. !form.customer?.id ||
  260. cart.length === 0
  261. "
  262. @submit="onSubmit"
  263. />
  264. </div>
  265. </div>
  266. </DashboardLayout>
  267. </template>