mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-31 13:41:09 -04:00 
			
		
		
		
	build version 400
This commit is contained in:
		| @ -1,262 +1,375 @@ | ||||
| <template> | ||||
|   <div class="payment-create main-content"> | ||||
|   <base-page class="relative payment-create"> | ||||
|     <form action="" @submit.prevent="submitPaymentData"> | ||||
|       <div class="page-header"> | ||||
|         <h3 class="page-title">{{ isEdit ? $t('payments.edit_payment') : $t('payments.new_payment') }}</h3> | ||||
|         <ol class="breadcrumb"> | ||||
|           <li class="breadcrumb-item"><router-link slot="item-title" to="/admin/dashboard">{{ $t('general.home') }}</router-link></li> | ||||
|           <li class="breadcrumb-item"><router-link slot="item-title" to="/admin/payments">{{ $tc('payments.payment', 2) }}</router-link></li> | ||||
|           <li class="breadcrumb-item">{{ isEdit ? $t('payments.edit_payment') : $t('payments.new_payment') }}</li> | ||||
|         </ol> | ||||
|         <div class="page-actions header-button-container"> | ||||
|           <base-button | ||||
|       <sw-page-header class="mb-5" :title="pageTitle"> | ||||
|         <sw-breadcrumb slot="breadcrumbs"> | ||||
|           <sw-breadcrumb-item | ||||
|             to="/admin/dashboard" | ||||
|             :title="$t('general.home')" | ||||
|           /> | ||||
|           <sw-breadcrumb-item | ||||
|             to="/admin/payments" | ||||
|             :title="$tc('payments.payment', 2)" | ||||
|           /> | ||||
|           <sw-breadcrumb-item | ||||
|             v-if="$route.name === 'payments.edit'" | ||||
|             to="#" | ||||
|             :title="$t('payments.edit_payment')" | ||||
|             active | ||||
|           /> | ||||
|           <sw-breadcrumb-item | ||||
|             v-else | ||||
|             to="#" | ||||
|             :title="$t('payments.new_payment')" | ||||
|             active | ||||
|           /> | ||||
|         </sw-breadcrumb> | ||||
|  | ||||
|         <template slot="actions"> | ||||
|           <sw-button | ||||
|             :loading="isLoading" | ||||
|             :disabled="isLoading" | ||||
|             icon="save" | ||||
|             color="theme" | ||||
|             type="submit"> | ||||
|             {{ isEdit ? $t('payments.update_payment') : $t('payments.save_payment') }} | ||||
|           </base-button> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="payment-card card"> | ||||
|         <div class="card-body"> | ||||
|           <div class="row"> | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.date') }}</label><span class="text-danger"> *</span> | ||||
|                 <base-date-picker | ||||
|                   v-model="formData.payment_date" | ||||
|                   :invalid="$v.formData.payment_date.$error" | ||||
|                   :calendar-button="true" | ||||
|                   calendar-button-icon="calendar" | ||||
|                   @change="$v.formData.payment_date.$touch()" | ||||
|                 /> | ||||
|                 <div v-if="$v.formData.payment_date.$error"> | ||||
|                   <span v-if="!$v.formData.payment_date.required" class="text-danger">{{ $t('validation.required') }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.payment_number') }}</label><span class="text-danger"> *</span> | ||||
|                 <base-prefix-input | ||||
|                   :invalid="$v.paymentNumAttribute.$error" | ||||
|                   v-model.trim="paymentNumAttribute" | ||||
|                   :prefix="paymentPrefix" | ||||
|                   @input="$v.paymentNumAttribute.$touch()" | ||||
|                 /> | ||||
|                 <div v-if="$v.paymentNumAttribute.$error"> | ||||
|                   <span v-if="!$v.paymentNumAttribute.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||
|                   <span v-if="!$v.paymentNumAttribute.numeric" class="text-danger">{{ $tc('validation.numbers_only') }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-6"> | ||||
|               <label class="form-label">{{ $t('payments.customer') }}</label><span class="text-danger"> *</span> | ||||
|               <base-select | ||||
|                 ref="baseSelect" | ||||
|                 v-model="customer" | ||||
|                 :invalid="$v.customer.$error" | ||||
|                 :options="customerList" | ||||
|                 :searchable="true" | ||||
|                 :show-labels="false" | ||||
|                 :allow-empty="false" | ||||
|                 :disabled="isEdit" | ||||
|                 :placeholder="$t('customers.select_a_customer')" | ||||
|                 label="name" | ||||
|                 track-by="id" | ||||
|             variant="primary" | ||||
|             type="submit" | ||||
|             size="lg" | ||||
|             class="hidden sm:flex" | ||||
|           > | ||||
|             <save-icon v-if="!isLoading" class="mr-2 -ml-1" /> | ||||
|             {{ | ||||
|               isEdit | ||||
|                 ? $t('payments.update_payment') | ||||
|                 : $t('payments.save_payment') | ||||
|             }} | ||||
|           </sw-button> | ||||
|         </template> | ||||
|       </sw-page-header> | ||||
|  | ||||
|       <base-loader v-if="isRequestOnGoing" :show-bg-overlay="true" /> | ||||
|  | ||||
|       <sw-card v-else> | ||||
|         <div class="grid gap-6 grid-col-1 md:grid-cols-2"> | ||||
|           <sw-input-group | ||||
|             :label="$t('payments.date')" | ||||
|             :error="DateError" | ||||
|             required | ||||
|           > | ||||
|             <base-date-picker | ||||
|               v-model="formData.payment_date" | ||||
|               :invalid="$v.formData.payment_date.$error" | ||||
|               :calendar-button="true" | ||||
|               class="mt-1" | ||||
|               calendar-button-icon="calendar" | ||||
|               @change="$v.formData.payment_date.$touch()" | ||||
|             /> | ||||
|           </sw-input-group> | ||||
|  | ||||
|           <sw-input-group | ||||
|             :label="$t('payments.payment_number')" | ||||
|             :error="paymentNumError" | ||||
|             required | ||||
|           > | ||||
|             <sw-input | ||||
|               :prefix="`${paymentPrefix} - `" | ||||
|               :invalid="$v.paymentNumAttribute.$error" | ||||
|               v-model.trim="paymentNumAttribute" | ||||
|               class="mt-1" | ||||
|               @input="$v.paymentNumAttribute.$touch()" | ||||
|             /> | ||||
|           </sw-input-group> | ||||
|  | ||||
|           <sw-input-group | ||||
|             :label="$t('payments.customer')" | ||||
|             :error="customerError" | ||||
|             required | ||||
|           > | ||||
|             <sw-select | ||||
|               v-model="customer" | ||||
|               :options="customers" | ||||
|               :searchable="true" | ||||
|               :show-labels="false" | ||||
|               :allow-empty="false" | ||||
|               :disabled="isEdit" | ||||
|               :placeholder="$t('customers.select_a_customer')" | ||||
|               label="name" | ||||
|               class="mt-1" | ||||
|               track-by="id" | ||||
|             /> | ||||
|           </sw-input-group> | ||||
|  | ||||
|           <sw-input-group :label="$t('payments.invoice')"> | ||||
|             <sw-select | ||||
|               v-model="invoice" | ||||
|               :options="invoiceList" | ||||
|               :searchable="true" | ||||
|               :show-labels="false" | ||||
|               :allow-empty="false" | ||||
|               :disabled="isEdit" | ||||
|               :placeholder="$t('invoices.select_invoice')" | ||||
|               :custom-label="invoiceWithAmount" | ||||
|               class="mt-1" | ||||
|               track-by="invoice_number" | ||||
|             /> | ||||
|           </sw-input-group> | ||||
|  | ||||
|           <sw-input-group | ||||
|             :label="$t('payments.amount')" | ||||
|             :error="amountError" | ||||
|             required | ||||
|           > | ||||
|             <div class="relative w-full mt-1"> | ||||
|               <sw-money | ||||
|                 v-model="amount" | ||||
|                 :currency="customerCurrency" | ||||
|                 :invalid="$v.formData.amount.$error" | ||||
|                 class="relative w-full focus:border focus:border-solid focus:border-primary-500" | ||||
|                 @input="$v.formData.amount.$touch()" | ||||
|               /> | ||||
|               <div v-if="$v.customer.$error"> | ||||
|                 <span v-if="!$v.customer.required" class="text-danger">{{ $tc('validation.required') }}</span> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.invoice') }}</label> | ||||
|                 <base-select | ||||
|                   v-model="invoice" | ||||
|                   :options="invoiceList" | ||||
|                   :searchable="true" | ||||
|                   :show-labels="false" | ||||
|                   :allow-empty="false" | ||||
|                   :disabled="isEdit" | ||||
|                   :placeholder="$t('invoices.select_invoice')" | ||||
|                   :custom-label="invoiceWithAmount" | ||||
|                   track-by="invoice_number" | ||||
|                 /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.amount') }}</label><span class="text-danger"> *</span> | ||||
|                 <div class="base-input"> | ||||
|                   <money | ||||
|                     :class="{'invalid' : $v.formData.amount.$error}" | ||||
|                     v-model="amount" | ||||
|                     v-bind="customerCurrency" | ||||
|                     class="input-field" | ||||
|                   /> | ||||
|                 </div> | ||||
|                 <div v-if="$v.formData.amount.$error"> | ||||
|                   <span v-if="!$v.formData.amount.required" class="text-danger">{{ $t('validation.required') }}</span> | ||||
|                   <span v-if="!$v.formData.amount.between && $v.formData.amount.numeric && amount <= 0" class="text-danger">{{ $t('validation.payment_greater_than_zero') }}</span> | ||||
|                   <span v-if="!$v.formData.amount.between && amount > 0" class="text-danger">{{ $t('validation.payment_greater_than_due_amount') }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-6"> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.payment_mode') }}</label> | ||||
|                 <base-select | ||||
|                   v-model="formData.payment_method" | ||||
|                   :options="paymentModes" | ||||
|                   :searchable="true" | ||||
|                   :show-labels="false" | ||||
|                   :placeholder="$t('payments.select_payment_mode')" | ||||
|                   label="name" | ||||
|           </sw-input-group> | ||||
|  | ||||
|           <sw-input-group :label="$t('payments.payment_mode')"> | ||||
|             <sw-select | ||||
|               v-model="formData.payment_method" | ||||
|               :options="paymentModes" | ||||
|               :searchable="true" | ||||
|               :show-labels="false" | ||||
|               :placeholder="$t('payments.select_payment_mode')" | ||||
|               label="name" | ||||
|               :maxHeight="150" | ||||
|               class="mt-1" | ||||
|             > | ||||
|               <div slot="afterList"> | ||||
|                 <button | ||||
|                   type="button" | ||||
|                   class="flex items-center justify-center w-full px-2 py-2 bg-gray-200 border-none outline-none text-primary-400" | ||||
|                   @click="addPaymentMode" | ||||
|                 > | ||||
|                   <div slot="afterList"> | ||||
|                     <button type="button" class="list-add-button" @click="addPaymentMode"> | ||||
|                       <font-awesome-icon class="icon" icon="cart-plus" /> | ||||
|                       <label>{{ $t('settings.customization.payments.add_payment_mode') }}</label> | ||||
|                     </button> | ||||
|                   </div> | ||||
|                 </base-select> | ||||
|                   <shopping-cart-icon class="h-5 mr-3 text-primary-400" /> | ||||
|                   <label>{{ | ||||
|                     $t('settings.customization.payments.add_payment_mode') | ||||
|                   }}</label> | ||||
|                 </button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-12 "> | ||||
|               <div class="form-group"> | ||||
|                 <label class="form-label">{{ $t('payments.note') }}</label> | ||||
|                 <base-text-area | ||||
|                   v-model="formData.notes" | ||||
|                   @input="$v.formData.notes.$touch()" | ||||
|                 /> | ||||
|                 <div v-if="$v.formData.notes.$error"> | ||||
|                   <span v-if="!$v.formData.notes.maxLength" class="text-danger">{{ $t('validation.notes_maxlength') }}</span> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="col-sm-12"> | ||||
|               <div class="form-group collapse-button-container"> | ||||
|                 <base-button | ||||
|                   :loading="isLoading" | ||||
|                   icon="save" | ||||
|                   color="theme" | ||||
|                   type="submit" | ||||
|                   class="collapse-button" | ||||
|                 > | ||||
|                   {{ $t('payments.save_payment') }} | ||||
|                 </base-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             </sw-select> | ||||
|           </sw-input-group> | ||||
|         </div> | ||||
|  | ||||
|         <div v-if="customFields.length > 0"> | ||||
|           <div class="grid gap-6 mt-6 grid-col-1 md:grid-cols-2"> | ||||
|             <sw-input-group | ||||
|               v-for="(field, index) in customFields" | ||||
|               :label="field.label" | ||||
|               :required="field.is_required ? true : false" | ||||
|               :key="index" | ||||
|             > | ||||
|               <component | ||||
|                 :type="field.type.label" | ||||
|                 :field="field" | ||||
|                 :isEdit="isEdit" | ||||
|                 :is="field.type + 'Field'" | ||||
|                 :invalid-fields="invalidFields" | ||||
|                 @update="setCustomFieldValue" | ||||
|               /> | ||||
|             </sw-input-group> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|  | ||||
|         <sw-popup | ||||
|           ref="notePopup" | ||||
|           class="my-6 text-sm font-semibold leading-5 text-primary-400" | ||||
|         > | ||||
|           <div slot="activator" class="float-right mt-1"> | ||||
|             + {{ $t('general.insert_note') }} | ||||
|           </div> | ||||
|           <note-select-popup type="Payment" @select="onSelectNote" /> | ||||
|         </sw-popup> | ||||
|  | ||||
|         <sw-input-group :label="$t('payments.note')" class="mt-6 mb-4"> | ||||
|           <base-custom-input | ||||
|             v-model="formData.notes" | ||||
|             :fields="PaymentFields" | ||||
|             class="mb-4" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-button | ||||
|           :disabled="isLoading" | ||||
|           :loading="isLoading" | ||||
|           variant="primary" | ||||
|           type="submit" | ||||
|           class="flex w-full mt-4 sm:hidden md:hidden" | ||||
|         > | ||||
|           <save-icon v-if="!isLoading" class="mr-2 -ml-1" /> | ||||
|           {{ | ||||
|             isEdit ? $t('payments.update_payment') : $t('payments.save_payment') | ||||
|           }} | ||||
|         </sw-button> | ||||
|       </sw-card> | ||||
|     </form> | ||||
|   </div> | ||||
|   </base-page> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import MultiSelect from 'vue-multiselect' | ||||
| import { validationMixin } from 'vuelidate' | ||||
| import moment from 'moment' | ||||
| const { required, between, maxLength, numeric } = require('vuelidate/lib/validators') | ||||
| import { ShoppingCartIcon } from '@vue-hero-icons/solid' | ||||
| import CustomFieldsMixin from '../../mixins/customFields' | ||||
|  | ||||
| const { required, between, numeric } = require('vuelidate/lib/validators') | ||||
|  | ||||
| export default { | ||||
|   components: { MultiSelect }, | ||||
|   mixins: [validationMixin], | ||||
|   data () { | ||||
|   mixins: [CustomFieldsMixin], | ||||
|  | ||||
|   components: { ShoppingCartIcon }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       formData: { | ||||
|         user_id: null, | ||||
|         payment_number: null, | ||||
|         payment_date: null, | ||||
|         amount: 0, | ||||
|         payment_date: new Date(), | ||||
|         amount: 100, | ||||
|         payment_method: null, | ||||
|         invoice_id: null, | ||||
|         notes: null, | ||||
|         payment_method_id: null | ||||
|         payment_method_id: null, | ||||
|       }, | ||||
|       money: { | ||||
|         decimal: '.', | ||||
|         thousands: ',', | ||||
|         prefix: '$ ', | ||||
|         precision: 2, | ||||
|         masked: false | ||||
|         masked: false, | ||||
|       }, | ||||
|       customer: null, | ||||
|       invoice: null, | ||||
|       customerList: [], | ||||
|       invoiceList: [], | ||||
|       isLoading: false, | ||||
|       isRequestOnGoing: false, | ||||
|       maxPayableAmount: Number.MAX_SAFE_INTEGER, | ||||
|       isSettingInitialData: true, | ||||
|       paymentNumAttribute: null, | ||||
|       paymentPrefix: '' | ||||
|       paymentPrefix: '', | ||||
|       PaymentFields: [ | ||||
|         'customer', | ||||
|         'company', | ||||
|         'customerCustom', | ||||
|         'payment', | ||||
|         'paymentCustom', | ||||
|       ], | ||||
|     } | ||||
|   }, | ||||
|   validations () { | ||||
|   validations() { | ||||
|     return { | ||||
|       customer: { | ||||
|         required | ||||
|         required, | ||||
|       }, | ||||
|       formData: { | ||||
|         payment_date: { | ||||
|           required | ||||
|           required, | ||||
|         }, | ||||
|         amount: { | ||||
|           required, | ||||
|           between: between(1, this.maxPayableAmount + 1) | ||||
|           between: between(1, this.maxPayableAmount + 1), | ||||
|         }, | ||||
|         notes: { | ||||
|           maxLength: maxLength(255) | ||||
|         } | ||||
|       }, | ||||
|       paymentNumAttribute: { | ||||
|         required, | ||||
|         numeric | ||||
|       } | ||||
|         numeric, | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapGetters('currency', [ | ||||
|       'defaultCurrencyForInput' | ||||
|     ]), | ||||
|     ...mapGetters('payment', [ | ||||
|       'paymentModes' | ||||
|     ]), | ||||
|     ...mapGetters('company', ['defaultCurrencyForInput']), | ||||
|     ...mapGetters('payment', ['paymentModes', 'selectedNote']), | ||||
|     ...mapGetters('customer', ['customers']), | ||||
|     amount: { | ||||
|       get: function () { | ||||
|         return this.formData.amount / 100 | ||||
|       }, | ||||
|       set: function (newValue) { | ||||
|         this.formData.amount = newValue * 100 | ||||
|       } | ||||
|       }, | ||||
|     }, | ||||
|     isEdit () { | ||||
|     pageTitle() { | ||||
|       if (this.$route.name === 'payments.edit') { | ||||
|         return this.$t('payments.edit_payment') | ||||
|       } | ||||
|       return this.$t('payments.new_payment') | ||||
|     }, | ||||
|     isEdit() { | ||||
|       if (this.$route.name === 'payments.edit') { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     customerCurrency () { | ||||
|     customerCurrency() { | ||||
|       if (this.customer && this.customer.currency) { | ||||
|         return { | ||||
|           decimal: this.customer.currency.decimal_separator, | ||||
|           thousands: this.customer.currency.thousand_separator, | ||||
|           prefix: this.customer.currency.symbol + ' ', | ||||
|           precision: this.customer.currency.precision, | ||||
|           masked: false | ||||
|           masked: false, | ||||
|         } | ||||
|       } else { | ||||
|         return this.defaultCurrencyForInput | ||||
|       } | ||||
|     } | ||||
|     }, | ||||
|     customerError() { | ||||
|       if (!this.$v.customer.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.customer.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     DateError() { | ||||
|       if (!this.$v.formData.payment_date.$error) { | ||||
|         return '' | ||||
|       } | ||||
|       if (!this.$v.formData.payment_date.required) { | ||||
|         return this.$t('validation.required') | ||||
|       } | ||||
|     }, | ||||
|     amountError() { | ||||
|       if (!this.$v.formData.amount.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.amount.required) { | ||||
|         return this.$t('validation.required') | ||||
|       } | ||||
|  | ||||
|       if ( | ||||
|         !this.$v.formData.amount.between && | ||||
|         this.$v.formData.amount.numeric && | ||||
|         this.amount <= 0 | ||||
|       ) { | ||||
|         return this.$t('validation.payment_greater_than_zero') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.formData.amount.between && this.amount > 0) { | ||||
|         return this.$t('validation.payment_greater_than_due_amount') | ||||
|       } | ||||
|     }, | ||||
|     paymentNumError() { | ||||
|       if (!this.$v.paymentNumAttribute.$error) { | ||||
|         return '' | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.paymentNumAttribute.required) { | ||||
|         return this.$tc('validation.required') | ||||
|       } | ||||
|  | ||||
|       if (!this.$v.paymentNumAttribute.numeric) { | ||||
|         return this.$tc('validation.numbers_only') | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   watch: { | ||||
|     customer (newValue) { | ||||
|     customer(newValue) { | ||||
|       this.formData.user_id = newValue.id | ||||
|       if (!this.isEdit) { | ||||
|         if (this.isSettingInitialData) { | ||||
| @ -270,16 +383,23 @@ export default { | ||||
|         this.fetchCustomerInvoices(newValue.id) | ||||
|       } | ||||
|     }, | ||||
|     invoice (newValue) { | ||||
|     selectedNote() { | ||||
|       if (this.selectedNote) { | ||||
|         this.formData.notes = this.selectedNote | ||||
|       } | ||||
|     }, | ||||
|     invoice(newValue) { | ||||
|       if (newValue) { | ||||
|         this.formData.invoice_id = newValue.id | ||||
|         if (!this.isEdit) { | ||||
|           this.setPaymentAmountByInvoiceData(newValue.id) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     }, | ||||
|   }, | ||||
|   async mounted () { | ||||
|   async mounted() { | ||||
|     this.$v.formData.$reset() | ||||
|     this.resetSelectedNote() | ||||
|     this.$nextTick(() => { | ||||
|       this.loadData() | ||||
|       if (this.$route.params.id && !this.isEdit) { | ||||
| @ -288,91 +408,159 @@ export default { | ||||
|     }) | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions('invoice', [ | ||||
|       'fetchInvoice' | ||||
|     ]), | ||||
|     ...mapActions('invoice', ['fetchInvoice', 'fetchInvoices']), | ||||
|  | ||||
|     ...mapActions('payment', [ | ||||
|       'fetchCreatePayment', | ||||
|       'addPayment', | ||||
|       'updatePayment', | ||||
|       'fetchEditPaymentData' | ||||
|       'fetchPayment', | ||||
|       'fetchPaymentModes', | ||||
|       'resetSelectedNote', | ||||
|     ]), | ||||
|     ...mapActions('modal', [ | ||||
|       'openModal' | ||||
|     ]), | ||||
|     invoiceWithAmount ({ invoice_number, due_amount }) { | ||||
|       return `${invoice_number} (${this.$utils.formatGraphMoney(due_amount, this.customer.currency)})` | ||||
|  | ||||
|     ...mapActions('company', ['fetchCompanySettings']), | ||||
|  | ||||
|     ...mapActions('modal', ['openModal']), | ||||
|  | ||||
|     ...mapActions('customer', ['fetchCustomers']), | ||||
|  | ||||
|     invoiceWithAmount({ invoice_number, due_amount }) { | ||||
|       return `${invoice_number} (${this.$utils.formatGraphMoney( | ||||
|         due_amount, | ||||
|         this.customer.currency | ||||
|       )})` | ||||
|     }, | ||||
|     async addPaymentMode () { | ||||
|  | ||||
|     async addPaymentMode() { | ||||
|       this.openModal({ | ||||
|         'title': this.$t('settings.customization.payments.add_payment_mode'), | ||||
|         'componentName': 'PaymentMode' | ||||
|         title: this.$t('settings.customization.payments.add_payment_mode'), | ||||
|         componentName: 'PaymentMode', | ||||
|       }) | ||||
|     }, | ||||
|     async loadData () { | ||||
|  | ||||
|     async checkAutoGenerate() { | ||||
|       let response = await this.fetchCompanySettings(['payment_auto_generate']) | ||||
|  | ||||
|       let response1 = await axios.get('/api/v1/next-number?key=payment') | ||||
|  | ||||
|       if (response.data && response.data.payment_auto_generate === 'YES') { | ||||
|         if (response1.data) { | ||||
|           this.paymentNumAttribute = response1.data.nextNumber | ||||
|           this.paymentPrefix = response1.data.prefix | ||||
|           return true | ||||
|         } | ||||
|       } else { | ||||
|         this.paymentPrefix = response1.data.prefix | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     async loadData() { | ||||
|       if (this.isEdit) { | ||||
|         let response = await this.fetchEditPaymentData(this.$route.params.id) | ||||
|         this.customerList = response.data.customers | ||||
|         this.formData = { ...response.data.payment } | ||||
|         this.isRequestOnGoing = true | ||||
|         let response = await this.fetchPayment(this.$route.params.id) | ||||
|         this.formData = { ...this.formData, ...response.data.payment } | ||||
|         this.customer = response.data.payment.user | ||||
|         this.formData.payment_date = moment(response.data.payment.payment_date, 'YYYY-MM-DD').toString() | ||||
|         this.formData.payment_date = moment( | ||||
|           response.data.payment.payment_date, | ||||
|           'YYYY-MM-DD' | ||||
|         ).toString() | ||||
|         this.formData.amount = parseFloat(response.data.payment.amount) | ||||
|         this.paymentPrefix = response.data.payment_prefix | ||||
|         this.paymentNumAttribute = response.data.nextPaymentNumber | ||||
|         this.formData.payment_method = response.data.payment.payment_method | ||||
|         if (response.data.payment.invoice !== null) { | ||||
|           this.maxPayableAmount = parseInt(response.data.payment.amount) + parseInt(response.data.payment.invoice.due_amount) | ||||
|           this.maxPayableAmount = | ||||
|             parseInt(response.data.payment.amount) + | ||||
|             parseInt(response.data.payment.invoice.due_amount) | ||||
|           this.invoice = response.data.payment.invoice | ||||
|         } | ||||
|         // this.fetchCustomerInvoices(this.customer.id) | ||||
|         let res = await this.fetchCustomFields({ | ||||
|           type: 'Payment', | ||||
|           limit: 'all', | ||||
|         }) | ||||
|         this.setEditCustomFields( | ||||
|           response.data.payment.fields, | ||||
|           res.data.customFields.data | ||||
|         ) | ||||
|  | ||||
|         if (this.formData.payment_method_id) { | ||||
|           await this.fetchPaymentModes({ limit: 'all' }) | ||||
|         } | ||||
|  | ||||
|         if (this.formData.user_id) { | ||||
|           await this.fetchCustomers({ limit: 'all' }) | ||||
|         } | ||||
|         this.isRequestOnGoing = false | ||||
|       } else { | ||||
|         let response = await this.fetchCreatePayment() | ||||
|         this.customerList = response.data.customers | ||||
|         this.paymentNumAttribute = response.data.nextPaymentNumberAttribute | ||||
|         this.paymentPrefix = response.data.payment_prefix | ||||
|         this.formData.payment_date = moment(new Date()).toString() | ||||
|         this.isRequestOnGoing = true | ||||
|         this.checkAutoGenerate() | ||||
|         this.setInitialCustomFields('Payment') | ||||
|         this.formData.payment_date = moment().toString() | ||||
|         this.fetchPaymentModes({ limit: 'all' }) | ||||
|         await this.fetchCustomers({ limit: 'all' }) | ||||
|         if (this.$route.query.customer) { | ||||
|           this.setPaymentCustomer(parseInt(this.$route.query.customer)) | ||||
|         } | ||||
|         this.isRequestOnGoing = false | ||||
|       } | ||||
|       return true | ||||
|     }, | ||||
|     async setInvoicePaymentData () { | ||||
|     setPaymentCustomer(id) { | ||||
|       this.customer = this.customers.find((c) => { | ||||
|         return c.id === id | ||||
|       }) | ||||
|     }, | ||||
|     async setInvoicePaymentData() { | ||||
|       let data = await this.fetchInvoice(this.$route.params.id) | ||||
|       this.customer = data.data.invoice.user | ||||
|       this.invoice = data.data.invoice | ||||
|     }, | ||||
|     async setPaymentAmountByInvoiceData (id) { | ||||
|     async setPaymentAmountByInvoiceData(id) { | ||||
|       let data = await this.fetchInvoice(id) | ||||
|       this.formData.amount = data.data.invoice.due_amount | ||||
|       this.maxPayableAmount = data.data.invoice.due_amount | ||||
|     }, | ||||
|     async fetchCustomerInvoices (userID) { | ||||
|       let response = await axios.get(`/api/invoices/unpaid/${userID}`) | ||||
|       if (response.data) { | ||||
|         this.invoiceList = response.data.invoices | ||||
|     async fetchCustomerInvoices(userId) { | ||||
|       let data = { | ||||
|         customer_id: userId, | ||||
|         status: 'UNPAID', | ||||
|       } | ||||
|       let response = await this.fetchInvoices(data) | ||||
|       this.invoiceList = response.data.invoices.data | ||||
|     }, | ||||
|     async submitPaymentData () { | ||||
|     async submitPaymentData() { | ||||
|       let validate = await this.touchCustomField() | ||||
|       this.$v.customer.$touch() | ||||
|       this.$v.formData.$touch() | ||||
|       if (this.$v.$invalid) { | ||||
|       if (this.$v.$invalid || validate.error) { | ||||
|         return true | ||||
|       } | ||||
|  | ||||
|       this.formData.payment_number = this.paymentPrefix + '-' + this.paymentNumAttribute | ||||
|       this.formData.payment_number = | ||||
|         this.paymentPrefix + '-' + this.paymentNumAttribute | ||||
|  | ||||
|       if (this.isEdit) { | ||||
|         let data = { | ||||
|           editData: { | ||||
|             ...this.formData, | ||||
|             payment_method_id: this.formData.payment_method ? this.formData.payment_method.id : null, | ||||
|             payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') | ||||
|             payment_method_id: this.formData.payment_method | ||||
|               ? this.formData.payment_method.id | ||||
|               : null, | ||||
|             payment_date: moment(this.formData.payment_date).format( | ||||
|               'YYYY-MM-DD' | ||||
|             ), | ||||
|           }, | ||||
|           id: this.$route.params.id | ||||
|           id: this.$route.params.id, | ||||
|         } | ||||
|         try { | ||||
|           this.isLoading = true | ||||
|           let response = await this.updatePayment(data) | ||||
|           if (response.data.success) { | ||||
|             this.isLoading = false | ||||
|             this.$router.push( | ||||
|               `/admin/payments/${response.data.payment.id}/view` | ||||
|             ) | ||||
|             window.toastr['success'](this.$t('payments.updated_message')) | ||||
|             this.$router.push('/admin/payments') | ||||
|             return true | ||||
|           } | ||||
|           if (response.data.error === 'invalid_amount') { | ||||
| @ -391,15 +579,19 @@ export default { | ||||
|       } else { | ||||
|         let data = { | ||||
|           ...this.formData, | ||||
|           payment_method_id: this.formData.payment_method ? this.formData.payment_method.id : null, | ||||
|           payment_date: moment(this.formData.payment_date).format('DD/MM/YYYY') | ||||
|           payment_method_id: this.formData.payment_method | ||||
|             ? this.formData.payment_method.id | ||||
|             : null, | ||||
|           payment_date: moment(this.formData.payment_date).format('YYYY-MM-DD'), | ||||
|         } | ||||
|         this.isLoading = true | ||||
|         try { | ||||
|           let response = await this.addPayment(data) | ||||
|           if (response.data.success) { | ||||
|             this.$router.push( | ||||
|               `/admin/payments/${response.data.payment.id}/view` | ||||
|             ) | ||||
|             window.toastr['success'](this.$t('payments.created_message')) | ||||
|             this.$router.push('/admin/payments') | ||||
|             this.isLoading = true | ||||
|             return true | ||||
|           } | ||||
| @ -417,7 +609,11 @@ export default { | ||||
|           window.toastr['error'](err.response.data.message) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|     }, | ||||
|     onSelectNote(data) { | ||||
|       this.formData.notes = '' + data.notes | ||||
|       this.$refs.notePopup.close() | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -1,306 +1,365 @@ | ||||
| <template> | ||||
|   <div class="payments main-content"> | ||||
|     <div class="page-header"> | ||||
|       <h3 class="page-title">{{ $t('payments.title') }}</h3> | ||||
|       <ol class="breadcrumb"> | ||||
|         <li class="breadcrumb-item"> | ||||
|           <router-link | ||||
|             slot="item-title" | ||||
|             to="dashboard"> | ||||
|             {{ $t('general.home') }} | ||||
|           </router-link> | ||||
|         </li> | ||||
|         <li class="breadcrumb-item"> | ||||
|           <router-link | ||||
|             slot="item-title" | ||||
|             to="#"> | ||||
|             {{ $tc('payments.payment',2) }} | ||||
|           </router-link> | ||||
|         </li> | ||||
|       </ol> | ||||
|       <div class="page-actions row"> | ||||
|         <div class="col-xs-2 mr-4"> | ||||
|           <base-button | ||||
|             v-show="totalPayments || filtersApplied" | ||||
|             :outline="true" | ||||
|             :icon="filterIcon" | ||||
|             color="theme" | ||||
|             right-icon | ||||
|             size="large" | ||||
|             @click="toggleFilter" | ||||
|           > | ||||
|             {{ $t('general.filter') }} | ||||
|           </base-button> | ||||
|         </div> | ||||
|         <router-link slot="item-title" class="col-xs-2" to="payments/create"> | ||||
|           <base-button | ||||
|             color="theme" | ||||
|             icon="plus" | ||||
|             size="large" | ||||
|           > | ||||
|             {{ $t('payments.add_payment') }} | ||||
|           </base-button> | ||||
|         </router-link> | ||||
|       </div> | ||||
|     </div> | ||||
|   <base-page class="payments"> | ||||
|     <sw-page-header :title="$t('payments.title')"> | ||||
|       <sw-breadcrumb slot="breadcrumbs"> | ||||
|         <sw-breadcrumb-item to="dashboard" :title="$t('general.home')" /> | ||||
|         <sw-breadcrumb-item to="#" :title="$tc('payments.payment', 2)" active /> | ||||
|       </sw-breadcrumb> | ||||
|  | ||||
|     <transition name="fade" mode="out-in"> | ||||
|       <div v-show="showFilters" class="filter-section"> | ||||
|         <div class="row"> | ||||
|           <div class="col-md-4"> | ||||
|             <label class="form-label">{{ $t('payments.customer') }}</label> | ||||
|             <base-customer-select | ||||
|               ref="customerSelect" | ||||
|               @select="onSelectCustomer" | ||||
|               @deselect="clearCustomerSearch" | ||||
|             /> | ||||
|           </div> | ||||
|           <div class="col-sm-4"> | ||||
|             <label for="">{{ $t('payments.payment_number') }}</label> | ||||
|             <base-input | ||||
|               v-model="filters.payment_number" | ||||
|               :placeholder="$t(payments.payment_number)" | ||||
|               name="payment_number" | ||||
|             /> | ||||
|           </div> | ||||
|           <div class="col-sm-4"> | ||||
|             <label class="form-label">{{ $t('payments.payment_mode') }}</label> | ||||
|             <base-select | ||||
|               v-model="filters.payment_mode" | ||||
|               :options="paymentModes" | ||||
|               :searchable="true" | ||||
|               :show-labels="false" | ||||
|               :placeholder="$t('payments.payment_mode')" | ||||
|               label="name" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|         <label class="clear-filter" @click="clearFilter">{{ $t('general.clear_all') }}</label> | ||||
|       </div> | ||||
|     </transition> | ||||
|  | ||||
|     <div v-cloak v-show="showEmptyScreen" class="col-xs-1 no-data-info" align="center"> | ||||
|       <capsule-icon class="mt-5 mb-4"/> | ||||
|       <div class="row" align="center"> | ||||
|         <label class="col title">{{ $t('payments.no_payments') }}</label> | ||||
|       </div> | ||||
|       <div class="row"> | ||||
|         <label class="description col mt-1" align="center">{{ $t('payments.list_of_payments') }}</label> | ||||
|       </div> | ||||
|       <div class="btn-container"> | ||||
|         <base-button | ||||
|           :outline="true" | ||||
|           color="theme" | ||||
|           class="mt-3" | ||||
|           size="large" | ||||
|           @click="$router.push('payments/create')" | ||||
|       <template slot="actions"> | ||||
|         <sw-button | ||||
|           v-show="totalPayments" | ||||
|           variant="primary-outline" | ||||
|           size="lg" | ||||
|           @click="toggleFilter" | ||||
|         > | ||||
|           {{ $t('payments.add_new_payment') }} | ||||
|         </base-button> | ||||
|       </div> | ||||
|     </div> | ||||
|           {{ $t('general.filter') }} | ||||
|           <component :is="filterIcon" class="w-4 h-4 ml-2 -mr-1" /> | ||||
|         </sw-button> | ||||
|  | ||||
|     <div v-show="!showEmptyScreen" class="table-container"> | ||||
|       <div class="table-actions mt-5"> | ||||
|         <p class="table-stats">{{ $t('general.showing') }}: <b>{{ payments.length }}</b> {{ $t('general.of') }} <b>{{ totalPayments }}</b></p> | ||||
|         <sw-button | ||||
|           tag-name="router-link" | ||||
|           to="payments/create" | ||||
|           variant="primary" | ||||
|           size="lg" | ||||
|           class="ml-4" | ||||
|         > | ||||
|           <plus-icon class="w-6 h-6 mr-1 -ml-2" /> | ||||
|           {{ $t('payments.add_payment') }} | ||||
|         </sw-button> | ||||
|       </template> | ||||
|     </sw-page-header> | ||||
|  | ||||
|         <transition name="fade"> | ||||
|           <v-dropdown v-if="selectedPayments.length" :show-arrow="false"> | ||||
|             <span slot="activator" href="#" class="table-actions-button dropdown-toggle"> | ||||
|     <slide-y-up-transition> | ||||
|       <sw-filter-wrapper v-show="showFilters" class="mt-3"> | ||||
|         <sw-input-group | ||||
|           :label="$t('payments.customer')" | ||||
|           color="black-light" | ||||
|           class="flex-1 mt-2" | ||||
|         > | ||||
|           <base-customer-select | ||||
|             ref="customerSelect" | ||||
|             @select="onSelectCustomer" | ||||
|             @deselect="clearCustomerSearch" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('payments.payment_number')" | ||||
|           class="flex-1 mt-2 lg:ml-6" | ||||
|         > | ||||
|           <sw-input | ||||
|             v-model="filters.payment_number" | ||||
|             :placeholder="$t(payments.payment_number)" | ||||
|             name="payment_number" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <sw-input-group | ||||
|           :label="$t('payments.payment_mode')" | ||||
|           class="flex-1 mt-2 lg:ml-6" | ||||
|         > | ||||
|           <sw-select | ||||
|             v-model="filters.payment_mode" | ||||
|             :options="paymentModes" | ||||
|             :searchable="true" | ||||
|             :show-labels="false" | ||||
|             :placeholder="$t('payments.payment_mode')" | ||||
|             label="name" | ||||
|           /> | ||||
|         </sw-input-group> | ||||
|  | ||||
|         <label | ||||
|           class="absolute text-sm leading-snug text-gray-900 cursor-pointer" | ||||
|           style="top: 10px; right: 15px" | ||||
|           @click="clearFilter" | ||||
|           >{{ $t('general.clear_all') }}</label | ||||
|         > | ||||
|       </sw-filter-wrapper> | ||||
|     </slide-y-up-transition> | ||||
|  | ||||
|     <sw-empty-table-placeholder | ||||
|       v-if="showEmptyScreen" | ||||
|       :title="$t('payments.no_payments')" | ||||
|       :description="$t('payments.list_of_payments')" | ||||
|     > | ||||
|       <capsule-icon class="mt-5 mb-4" /> | ||||
|  | ||||
|       <sw-button | ||||
|         slot="actions" | ||||
|         tag-name="router-link" | ||||
|         to="/admin/payments/create" | ||||
|         size="lg" | ||||
|         variant="primary-outline" | ||||
|       > | ||||
|         <plus-icon class="w-6 h-6 mr-1 -ml-2" /> | ||||
|         {{ $t('payments.add_new_payment') }} | ||||
|       </sw-button> | ||||
|     </sw-empty-table-placeholder> | ||||
|  | ||||
|     <div v-show="!showEmptyScreen" class="relative table-container"> | ||||
|       <div | ||||
|         class="relative flex items-center justify-between h-10 mt-5 list-none border-b-2 border-gray-200 border-solid" | ||||
|       > | ||||
|         <p class="text-sm"> | ||||
|           {{ $t('general.showing') }}: <b>{{ payments.length }}</b> | ||||
|           {{ $t('general.of') }} <b>{{ totalPayments }}</b> | ||||
|         </p> | ||||
|  | ||||
|         <sw-transition type="fade"> | ||||
|           <sw-dropdown v-if="selectedPayments.length"> | ||||
|             <span | ||||
|               slot="activator" | ||||
|               class="flex block text-sm font-medium cursor-pointer select-none text-primary-400" | ||||
|             > | ||||
|               {{ $t('general.actions') }} | ||||
|               <chevron-down-icon class="h-5" /> | ||||
|             </span> | ||||
|             <v-dropdown-item> | ||||
|               <div class="dropdown-item" @click="removeMultiplePayments"> | ||||
|                 <font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" /> | ||||
|                 {{ $t('general.delete') }} | ||||
|               </div> | ||||
|             </v-dropdown-item> | ||||
|           </v-dropdown> | ||||
|         </transition> | ||||
|  | ||||
|             <sw-dropdown-item @click="removeMultiplePayments"> | ||||
|               <trash-icon class="h-5 mr-3 text-gray-600" /> | ||||
|               {{ $t('general.delete') }} | ||||
|             </sw-dropdown-item> | ||||
|           </sw-dropdown> | ||||
|         </sw-transition> | ||||
|       </div> | ||||
|  | ||||
|       <div class="custom-control custom-checkbox"> | ||||
|         <input | ||||
|           id="select-all" | ||||
|       <div class="absolute z-10 items-center pl-4 mt-2 select-none md:mt-12"> | ||||
|         <sw-checkbox | ||||
|           v-model="selectAllFieldStatus" | ||||
|           type="checkbox" | ||||
|           class="custom-control-input" | ||||
|           variant="primary" | ||||
|           size="sm" | ||||
|           class="hidden md:inline" | ||||
|           @change="selectAllPayments" | ||||
|         > | ||||
|         <label v-show="!isRequestOngoing" for="select-all" class="custom-control-label selectall"> | ||||
|           <span class="select-all-label">{{ $t('general.select_all') }} </span> | ||||
|         </label> | ||||
|         /> | ||||
|  | ||||
|         <sw-checkbox | ||||
|           v-model="selectAllFieldStatus" | ||||
|           :label="$t('general.select_all')" | ||||
|           variant="primary" | ||||
|           size="sm" | ||||
|           class="md:hidden" | ||||
|           @change="selectAllPayments" | ||||
|         /> | ||||
|       </div> | ||||
|  | ||||
|       <table-component | ||||
|       <sw-table-component | ||||
|         ref="table" | ||||
|         :data="fetchData" | ||||
|         :show-filter="false" | ||||
|         table-class="table" | ||||
|       > | ||||
|         <table-column | ||||
|         <sw-table-column | ||||
|           :sortable="false" | ||||
|           :filterable="false" | ||||
|           cell-class="no-click" | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <div class="custom-control custom-checkbox"> | ||||
|               <input | ||||
|                 :id="row.id" | ||||
|                 v-model="selectField" | ||||
|                 :value="row.id" | ||||
|                 type="checkbox" | ||||
|                 class="custom-control-input" | ||||
|               > | ||||
|               <label :for="row.id" class="custom-control-label" /> | ||||
|             </div> | ||||
|           </template> | ||||
|         </table-column> | ||||
|         <table-column | ||||
|           <div slot-scope="row" class="relative block"> | ||||
|             <sw-checkbox | ||||
|               :id="row.id" | ||||
|               v-model="selectField" | ||||
|               :value="row.id" | ||||
|               variant="primary" | ||||
|               size="sm" | ||||
|             /> | ||||
|           </div> | ||||
|         </sw-table-column> | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="true" | ||||
|           :label="$t('payments.date')" | ||||
|           sort-as="payment_date" | ||||
|           show="formattedPaymentDate" | ||||
|         /> | ||||
|         <table-column | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="true" | ||||
|           :label="$t('payments.payment_number')" | ||||
|           show="payment_number" | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('payments.payment_number') }}</span> | ||||
|             <router-link | ||||
|               :to="{ path: `payments/${row.id}/view` }" | ||||
|               class="font-medium text-primary-500" | ||||
|             > | ||||
|               {{ row.payment_number }} | ||||
|             </router-link> | ||||
|           </template> | ||||
|         </sw-table-column> | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="true" | ||||
|           :label="$t('payments.customer')" | ||||
|           show="name" | ||||
|         /> | ||||
|         <table-column | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="true" | ||||
|           :label="$t('payments.payment_mode')" | ||||
|           show="payment_mode" | ||||
|         /> | ||||
|         <table-column | ||||
|           :label="$t('payments.payment_number')" | ||||
|           show="payment_number" | ||||
|         /> | ||||
|         <table-column | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('payments.payment_mode') }}</span> | ||||
|             <span> | ||||
|               {{ row.payment_mode ? row.payment_mode : 'Not selected' }} | ||||
|             </span> | ||||
|           </template> | ||||
|         </sw-table-column> | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="true" | ||||
|           :label="$t('payments.invoice')" | ||||
|           sort-as="invoice_id" | ||||
|           show="invoice.invoice_number" | ||||
|         /> | ||||
|         <table-column | ||||
|           :label="$t('payments.amount')" | ||||
|           show="invoice_number" | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('invoices.invoice_number') }}</span> | ||||
|             <span> | ||||
|               {{ row.invoice_number ? row.invoice_number : 'No Invoice' }} | ||||
|             </span> | ||||
|           </template> | ||||
|         </sw-table-column> | ||||
|  | ||||
|         <sw-table-column :sortable="true" :label="$t('payments.amount')"> | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('payments.amount') }}</span> | ||||
|             <div v-html="$utils.formatMoney(row.amount, row.user.currency)" /> | ||||
|           </template> | ||||
|         </table-column> | ||||
|         <table-column | ||||
|         </sw-table-column> | ||||
|  | ||||
|         <sw-table-column | ||||
|           :sortable="false" | ||||
|           :filterable="false" | ||||
|           cell-class="action-dropdown no-click" | ||||
|           cell-class="action-dropdown" | ||||
|         > | ||||
|           <template slot-scope="row"> | ||||
|             <span>{{ $t('payments.action') }}</span> | ||||
|             <v-dropdown> | ||||
|               <a slot="activator" href="#"> | ||||
|                 <dot-icon /> | ||||
|               </a> | ||||
|               <v-dropdown-item> | ||||
|             <sw-dropdown> | ||||
|               <dot-icon slot="activator" /> | ||||
|  | ||||
|                 <router-link :to="{path: `payments/${row.id}/edit`}" class="dropdown-item"> | ||||
|                   <font-awesome-icon :icon="['fas', 'pencil-alt']" class="dropdown-item-icon" /> | ||||
|                   {{ $t('general.edit') }} | ||||
|                 </router-link> | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`payments/${row.id}/edit`" | ||||
|               > | ||||
|                 <pencil-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.edit') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item> | ||||
|               <sw-dropdown-item | ||||
|                 tag-name="router-link" | ||||
|                 :to="`payments/${row.id}/view`" | ||||
|               > | ||||
|                 <eye-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.view') }} | ||||
|               </sw-dropdown-item> | ||||
|  | ||||
|                 <router-link :to="{path: `payments/${row.id}/view`}" class="dropdown-item"> | ||||
|                   <font-awesome-icon icon="eye" class="dropdown-item-icon" /> | ||||
|                   {{ $t('general.view') }} | ||||
|                 </router-link> | ||||
|  | ||||
|               </v-dropdown-item> | ||||
|               <v-dropdown-item> | ||||
|                 <div class="dropdown-item" @click="removePayment(row.id)"> | ||||
|                   <font-awesome-icon :icon="['fas', 'trash']" class="dropdown-item-icon" /> | ||||
|                   {{ $t('general.delete') }} | ||||
|                 </div> | ||||
|               </v-dropdown-item> | ||||
|             </v-dropdown> | ||||
|               <sw-dropdown-item @click="removePayment(row.id)"> | ||||
|                 <trash-icon class="h-5 mr-3 text-gray-600" /> | ||||
|                 {{ $t('general.delete') }} | ||||
|               </sw-dropdown-item> | ||||
|             </sw-dropdown> | ||||
|           </template> | ||||
|         </table-column> | ||||
|       </table-component> | ||||
|         </sw-table-column> | ||||
|       </sw-table-component> | ||||
|     </div> | ||||
|   </div> | ||||
|   </base-page> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| import { SweetModal, SweetModalTab } from 'sweet-modal-vue' | ||||
| import CapsuleIcon from '../../components/icon/CapsuleIcon' | ||||
| import BaseButton from '../../../js/components/base/BaseButton' | ||||
| import CapsuleIcon from '@/components/icon/CapsuleIcon' | ||||
| import { | ||||
|   PlusIcon, | ||||
|   FilterIcon, | ||||
|   XIcon, | ||||
|   ChevronDownIcon, | ||||
|   EyeIcon, | ||||
|   PencilIcon, | ||||
|   TrashIcon, | ||||
| } from '@vue-hero-icons/solid' | ||||
|  | ||||
| export default { | ||||
|   components: { | ||||
|     'capsule-icon': CapsuleIcon, | ||||
|     'SweetModal': SweetModal, | ||||
|     'SweetModalTab': SweetModalTab, | ||||
|     BaseButton | ||||
|     CapsuleIcon, | ||||
|     PlusIcon, | ||||
|     FilterIcon, | ||||
|     XIcon, | ||||
|     ChevronDownIcon, | ||||
|     EyeIcon, | ||||
|     PencilIcon, | ||||
|     TrashIcon, | ||||
|   }, | ||||
|   data () { | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       showFilters: false, | ||||
|       sortedBy: 'created_at', | ||||
|       filtersApplied: false, | ||||
|       isRequestOngoing: true, | ||||
|  | ||||
|       filters: { | ||||
|         customer: null, | ||||
|         customer: '', | ||||
|         payment_mode: '', | ||||
|         payment_number: '' | ||||
|       } | ||||
|         payment_number: '', | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     showEmptyScreen () { | ||||
|       return !this.totalPayments && !this.isRequestOngoing && !this.filtersApplied | ||||
|     showEmptyScreen() { | ||||
|       return !this.totalPayments && !this.isRequestOngoing | ||||
|     }, | ||||
|     filterIcon () { | ||||
|       return (this.showFilters) ? 'times' : 'filter' | ||||
|  | ||||
|     filterIcon() { | ||||
|       return this.showFilters ? 'x-icon' : 'filter-icon' | ||||
|     }, | ||||
|     ...mapGetters('customer', [ | ||||
|       'customers' | ||||
|     ]), | ||||
|  | ||||
|     ...mapGetters('customer', ['customers']), | ||||
|  | ||||
|     ...mapGetters('payment', [ | ||||
|       'selectedPayments', | ||||
|       'totalPayments', | ||||
|       'payments', | ||||
|       'selectAllField', | ||||
|       'paymentModes' | ||||
|       'paymentModes', | ||||
|     ]), | ||||
|  | ||||
|     selectField: { | ||||
|       get: function () { | ||||
|         return this.selectedPayments | ||||
|       }, | ||||
|       set: function (val) { | ||||
|         this.selectPayment(val) | ||||
|       } | ||||
|       }, | ||||
|     }, | ||||
|  | ||||
|     selectAllFieldStatus: { | ||||
|       get: function () { | ||||
|         return this.selectAllField | ||||
|       }, | ||||
|       set: function (val) { | ||||
|         this.setSelectAllState(val) | ||||
|       } | ||||
|     } | ||||
|       }, | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     filters: { | ||||
|       handler: 'setFilters', | ||||
|       deep: true | ||||
|     } | ||||
|       deep: true, | ||||
|     }, | ||||
|   }, | ||||
|   mounted () { | ||||
|     this.fetchCustomers() | ||||
|  | ||||
|   mounted() { | ||||
|     this.fetchPaymentModes({ limit: 'all' }) | ||||
|   }, | ||||
|   destroyed () { | ||||
|  | ||||
|   destroyed() { | ||||
|     if (this.selectAllField) { | ||||
|       this.selectAllPayments() | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     ...mapActions('payment', [ | ||||
|       'fetchPayments', | ||||
| @ -308,25 +367,25 @@ export default { | ||||
|       'selectPayment', | ||||
|       'deletePayment', | ||||
|       'deleteMultiplePayments', | ||||
|       'setSelectAllState' | ||||
|       'setSelectAllState', | ||||
|       'fetchPaymentModes', | ||||
|     ]), | ||||
|     ...mapActions('customer', [ | ||||
|       'fetchCustomers' | ||||
|     ]), | ||||
|     async fetchData ({ page, filter, sort }) { | ||||
|  | ||||
|     async fetchData({ page, filter, sort }) { | ||||
|       let data = { | ||||
|         customer_id: this.filters.customer !== null ? this.filters.customer.id : '', | ||||
|         customer_id: this.filters.customer ? this.filters.customer.id : '', | ||||
|         payment_method_id: | ||||
|           this.filters.payment_mode !== null | ||||
|             ? this.filters.payment_mode.id | ||||
|             : '', | ||||
|         payment_number: this.filters.payment_number, | ||||
|         payment_method_id: this.filters.payment_mode ? this.filters.payment_mode.id : '', | ||||
|         orderByField: sort.fieldName || 'created_at', | ||||
|         orderBy: sort.order || 'desc', | ||||
|         page | ||||
|         page, | ||||
|       } | ||||
|  | ||||
|       this.isRequestOngoing = true | ||||
|  | ||||
|       let response = await this.fetchPayments(data) | ||||
|  | ||||
|       this.isRequestOngoing = false | ||||
|  | ||||
|       return { | ||||
| @ -334,71 +393,75 @@ export default { | ||||
|         pagination: { | ||||
|           totalPages: response.data.payments.last_page, | ||||
|           currentPage: page, | ||||
|           count: response.data.payments.scount | ||||
|         } | ||||
|           count: response.data.payments.count, | ||||
|         }, | ||||
|       } | ||||
|     }, | ||||
|     refreshTable () { | ||||
|  | ||||
|     refreshTable() { | ||||
|       this.$refs.table.refresh() | ||||
|     }, | ||||
|     setFilters () { | ||||
|       this.filtersApplied = true | ||||
|  | ||||
|     setFilters() { | ||||
|       this.refreshTable() | ||||
|     }, | ||||
|     clearFilter () { | ||||
|  | ||||
|     clearFilter() { | ||||
|       if (this.filters.customer) { | ||||
|         this.$refs.customerSelect.$refs.baseSelect.removeElement(this.filters.customer) | ||||
|         this.$refs.customerSelect.$refs.baseSelect.removeElement( | ||||
|           this.filters.customer | ||||
|         ) | ||||
|       } | ||||
|  | ||||
|       this.filters = { | ||||
|         customer: null, | ||||
|         customer: '', | ||||
|         payment_mode: '', | ||||
|         payment_number: '' | ||||
|         payment_number: '', | ||||
|       } | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         this.filtersApplied = false | ||||
|       }) | ||||
|     }, | ||||
|     toggleFilter () { | ||||
|       if (this.showFilters && this.filtersApplied) { | ||||
|  | ||||
|     toggleFilter() { | ||||
|       if (this.showFilters) { | ||||
|         this.clearFilter() | ||||
|         this.refreshTable() | ||||
|       } | ||||
|  | ||||
|       this.showFilters = !this.showFilters | ||||
|     }, | ||||
|     onSelectCustomer (customer) { | ||||
|  | ||||
|     onSelectCustomer(customer) { | ||||
|       this.filters.customer = customer | ||||
|     }, | ||||
|     async removePayment (id) { | ||||
|       this.id = id | ||||
|  | ||||
|     async removePayment(id) { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('payments.confirm_delete'), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|         dangerMode: true, | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let res = await this.deletePayment(this.id) | ||||
|           let res = await this.deletePayment({ ids: [id] }) | ||||
|  | ||||
|           if (res.data.success) { | ||||
|             window.toastr['success'](this.$tc('payments.deleted_message', 1)) | ||||
|             this.$refs.table.refresh() | ||||
|             return true | ||||
|           } else if (res.data.error) { | ||||
|             window.toastr['error'](res.data.message) | ||||
|           } | ||||
|  | ||||
|           window.toastr['error'](res.data.message) | ||||
|           return true | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     async removeMultiplePayments () { | ||||
|  | ||||
|     async removeMultiplePayments() { | ||||
|       swal({ | ||||
|         title: this.$t('general.are_you_sure'), | ||||
|         text: this.$tc('payments.confirm_delete', 2), | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|         dangerMode: true, | ||||
|       }).then(async (willDelete) => { | ||||
|         if (willDelete) { | ||||
|           let request = await this.deleteMultiplePayments() | ||||
| @ -411,21 +474,24 @@ export default { | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     async clearCustomerSearch (removedOption, id) { | ||||
|  | ||||
|     async clearCustomerSearch(removedOption, id) { | ||||
|       this.filters.customer = '' | ||||
|       this.$refs.table.refresh() | ||||
|       this.refreshTable() | ||||
|     }, | ||||
|     showModel (selectedRow) { | ||||
|  | ||||
|     showModel(selectedRow) { | ||||
|       this.selectedRow = selectedRow | ||||
|       this.$refs.Delete_modal.open() | ||||
|     }, | ||||
|     async removeSelectedItems () { | ||||
|  | ||||
|     async removeSelectedItems() { | ||||
|       this.$refs.Delete_modal.close() | ||||
|       await this.selectedRow.forEach(row => { | ||||
|       await this.selectedRow.forEach((row) => { | ||||
|         this.deletePayment(this.id) | ||||
|       }) | ||||
|       this.$refs.table.refresh() | ||||
|     } | ||||
|   } | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -1,176 +1,225 @@ | ||||
| <template> | ||||
|   <div v-if="payment" class="main-content payment-view-page"> | ||||
|     <div class="page-header"> | ||||
|       <h3 class="page-title">{{ payment.payment_number }}</h3> | ||||
|       <div class="page-actions row"> | ||||
|         <base-button | ||||
|           :loading="isSendingEmail" | ||||
|   <base-page v-if="payment" class="xl:pl-96"> | ||||
|     <sw-page-header :title="pageTitle"> | ||||
|       <template slot="actions"> | ||||
|         <sw-button | ||||
|           :disabled="isSendingEmail" | ||||
|           color="theme" | ||||
|           variant="primary" | ||||
|           @click="onPaymentSend" | ||||
|         > | ||||
|           {{ $t('payments.send_payment_receipt') }} | ||||
|         </base-button> | ||||
|         <v-dropdown | ||||
|           :close-on-select="true" | ||||
|           align="left" | ||||
|           class="filter-container" | ||||
|         > | ||||
|           <a slot="activator" href="#"> | ||||
|             <base-button color="theme"> | ||||
|               <font-awesome-icon icon="ellipsis-h" /> | ||||
|             </base-button> | ||||
|           </a> | ||||
|           <v-dropdown-item> | ||||
|             <div class="dropdown-item" @click="copyPdfUrl"> | ||||
|               <font-awesome-icon | ||||
|                 :icon="['fas', 'link']" | ||||
|                 class="dropdown-item-icon" | ||||
|               /> | ||||
|               {{ $t('general.copy_pdf_url') }} | ||||
|             </div> | ||||
|             <router-link | ||||
|               :to="{ path: `/admin/payments/${$route.params.id}/edit` }" | ||||
|               class="dropdown-item" | ||||
|             > | ||||
|               <font-awesome-icon | ||||
|                 :icon="['fas', 'pencil-alt']" | ||||
|                 class="dropdown-item-icon" | ||||
|               /> | ||||
|               {{ $t('general.edit') }} | ||||
|             </router-link> | ||||
|             <div class="dropdown-item" @click="removePayment($route.params.id)"> | ||||
|               <font-awesome-icon | ||||
|                 :icon="['fas', 'trash']" | ||||
|                 class="dropdown-item-icon" | ||||
|               /> | ||||
|               {{ $t('general.delete') }} | ||||
|             </div> | ||||
|           </v-dropdown-item> | ||||
|         </v-dropdown> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="payment-sidebar"> | ||||
|       <div class="side-header"> | ||||
|         <base-input | ||||
|         </sw-button> | ||||
|         <sw-dropdown class="ml-3"> | ||||
|           <sw-button slot="activator" variant="primary" class="h-10"> | ||||
|             <dots-horizontal-icon class="h-5" /> | ||||
|           </sw-button> | ||||
|  | ||||
|           <sw-dropdown-item @click="copyPdfUrl"> | ||||
|             <link-icon class="h-5 mr-3 text-gray-600" /> | ||||
|             {{ $t('general.copy_pdf_url') }} | ||||
|           </sw-dropdown-item> | ||||
|  | ||||
|           <sw-dropdown-item | ||||
|             tag-name="router-link" | ||||
|             :to="`/admin/payments/${$route.params.id}/edit`" | ||||
|           > | ||||
|             <pencil-icon class="h-5 mr-3 text-gray-600" /> | ||||
|             {{ $t('general.edit') }} | ||||
|           </sw-dropdown-item> | ||||
|  | ||||
|           <sw-dropdown-item @click="removePayment($route.params.id)"> | ||||
|             <trash-icon class="h-5 mr-3 text-gray-600" /> | ||||
|             {{ $t('general.delete') }} | ||||
|           </sw-dropdown-item> | ||||
|         </sw-dropdown> | ||||
|       </template> | ||||
|     </sw-page-header> | ||||
|  | ||||
|     <!-- sidebar --> | ||||
|     <div | ||||
|       class="fixed top-0 left-0 hidden h-full pt-16 pb-4 ml-56 bg-white xl:ml-64 w-88 xl:block" | ||||
|     > | ||||
|       <div | ||||
|         class="flex items-center justify-between px-4 pt-8 pb-2 border border-gray-200 border-solid height-full" | ||||
|       > | ||||
|         <sw-input | ||||
|           v-model="searchData.searchText" | ||||
|           :placeholder="$t('general.search')" | ||||
|           input-class="inv-search" | ||||
|           icon="search" | ||||
|           type="text" | ||||
|           align-icon="right" | ||||
|           class="mb-6" | ||||
|           variant="gray" | ||||
|           @input="onSearch" | ||||
|         /> | ||||
|         <div class="btn-group ml-3" role="group" aria-label="First group"> | ||||
|           <v-dropdown | ||||
|             :close-on-select="false" | ||||
|             align="left" | ||||
|             class="filter-container" | ||||
|           > | ||||
|             <a slot="activator" href="#"> | ||||
|               <base-button | ||||
|                 class="inv-button inv-filter-fields-btn" | ||||
|                 color="default" | ||||
|                 size="medium" | ||||
|               > | ||||
|                 <font-awesome-icon icon="filter" /> | ||||
|               </base-button> | ||||
|             </a> | ||||
|             <div class="filter-title"> | ||||
|         > | ||||
|           <search-icon slot="rightIcon" class="h-5" /> | ||||
|         </sw-input> | ||||
|  | ||||
|         <div class="flex mb-6 ml-3" role="group" aria-label="First group"> | ||||
|           <sw-dropdown position="bottom-start"> | ||||
|             <sw-button slot="activator" size="md" variant="gray-light"> | ||||
|               <filter-icon class="h-5" /> | ||||
|             </sw-button> | ||||
|  | ||||
|             <div | ||||
|               class="px-2 pb-2 mb-1 text-sm border-b border-gray-200 border-solid" | ||||
|             > | ||||
|               {{ $t('general.sort_by') }} | ||||
|             </div> | ||||
|             <div class="filter-items"> | ||||
|               <input | ||||
|                 id="filter_invoice_number" | ||||
|                 v-model="searchData.orderByField" | ||||
|                 type="radio" | ||||
|                 name="filter" | ||||
|                 class="inv-radio" | ||||
|                 value="invoice_number" | ||||
|                 @change="onSearch" | ||||
|               /> | ||||
|               <label class="inv-label" for="filter_invoice_number">{{ | ||||
|                 $t('invoices.title') | ||||
|               }}</label> | ||||
|             </div> | ||||
|             <div class="filter-items"> | ||||
|               <input | ||||
|                 id="filter_payment_date" | ||||
|                 v-model="searchData.orderByField" | ||||
|                 type="radio" | ||||
|                 name="filter" | ||||
|                 class="inv-radio" | ||||
|                 value="payment_date" | ||||
|                 @change="onSearch" | ||||
|               /> | ||||
|               <label class="inv-label" for="filter_payment_date">{{ | ||||
|                 $t('payments.date') | ||||
|               }}</label> | ||||
|             </div> | ||||
|             <div class="filter-items"> | ||||
|               <input | ||||
|                 id="filter_payment_number" | ||||
|                 v-model="searchData.orderByField" | ||||
|                 type="radio" | ||||
|                 name="filter" | ||||
|                 class="inv-radio" | ||||
|                 value="payment_number" | ||||
|                 @change="onSearch" | ||||
|               /> | ||||
|               <label class="inv-label" for="filter_payment_number">{{ | ||||
|                 $t('payments.payment_number') | ||||
|               }}</label> | ||||
|             </div> | ||||
|           </v-dropdown> | ||||
|           <base-button | ||||
|  | ||||
|             <sw-dropdown-item class="flex cursor-pointer"> | ||||
|               <sw-input-group class="-mt-3 font-normal"> | ||||
|                 <sw-radio | ||||
|                   :label="$t('invoices.title')" | ||||
|                   size="sm" | ||||
|                   id="filter_invoice_number" | ||||
|                   v-model="searchData.orderByField" | ||||
|                   name="filter" | ||||
|                   value="invoice_number" | ||||
|                   @change="onSearch" | ||||
|                 /> | ||||
|               </sw-input-group> | ||||
|             </sw-dropdown-item> | ||||
|  | ||||
|             <sw-dropdown-item class="flex cursor-pointer"> | ||||
|               <sw-input-group class="-mt-3 font-normal"> | ||||
|                 <sw-radio | ||||
|                   :label="$t('payments.date')" | ||||
|                   size="sm" | ||||
|                   id="filter_payment_date" | ||||
|                   v-model="searchData.orderByField" | ||||
|                   name="filter" | ||||
|                   value="payment_date" | ||||
|                   @change="onSearch" | ||||
|                 /> | ||||
|               </sw-input-group> | ||||
|             </sw-dropdown-item> | ||||
|  | ||||
|             <sw-dropdown-item class="flex cursor-pointer"> | ||||
|               <sw-input-group class="-mt-3 font-normal"> | ||||
|                 <sw-radio | ||||
|                   id="filter_payment_number" | ||||
|                   :label="$t('payments.payment_number')" | ||||
|                   v-model="searchData.orderByField" | ||||
|                   size="sm" | ||||
|                   name="filter" | ||||
|                   value="payment_number" | ||||
|                   @change="onSearch" | ||||
|                 /> | ||||
|               </sw-input-group> | ||||
|             </sw-dropdown-item> | ||||
|           </sw-dropdown> | ||||
|  | ||||
|           <sw-button | ||||
|             class="ml-1" | ||||
|             v-tooltip.top-center="{ content: getOrderName }" | ||||
|             class="inv-button inv-filter-sorting-btn" | ||||
|             color="default" | ||||
|             size="medium" | ||||
|             size="md" | ||||
|             variant="gray-light" | ||||
|             @click="sortData" | ||||
|           > | ||||
|             <font-awesome-icon v-if="getOrderBy" icon="sort-amount-up" /> | ||||
|             <font-awesome-icon v-else icon="sort-amount-down" /> | ||||
|           </base-button> | ||||
|             <sort-ascending-icon v-if="getOrderBy" class="h-5" /> | ||||
|             <sort-descending-icon v-else class="h-5" /> | ||||
|           </sw-button> | ||||
|         </div> | ||||
|       </div> | ||||
|       <base-loader v-if="isSearching" /> | ||||
|       <div v-else class="side-content"> | ||||
|  | ||||
|       <base-loader v-if="isSearching" :show-bg-overlay="true" /> | ||||
|  | ||||
|       <div | ||||
|         v-else | ||||
|         class="h-full pb-32 overflow-y-scroll border-l border-gray-200 border-solid sw-scroll" | ||||
|       > | ||||
|         <router-link | ||||
|           v-for="(payment, index) in payments" | ||||
|           :to="`/admin/payments/${payment.id}/view`" | ||||
|           :id="'payment-' + payment.id" | ||||
|           :key="index" | ||||
|           class="side-payment" | ||||
|           :class="[ | ||||
|             'flex justify-between p-4 items-center cursor-pointer hover:bg-gray-100 border-l-4 border-transparent', | ||||
|             { | ||||
|               'bg-gray-100 border-l-4 border-primary-500 border-solid': hasActiveUrl( | ||||
|                 payment.id | ||||
|               ), | ||||
|             }, | ||||
|           ]" | ||||
|           style="border-bottom: 1px solid rgba(185, 193, 209, 0.41)" | ||||
|         > | ||||
|           <div class="left"> | ||||
|             <div class="inv-name">{{ payment.user.name }}</div> | ||||
|             <div class="inv-number">{{ payment.payment_number }}</div> | ||||
|             <div class="inv-number">{{ payment.invoice_number }}</div> | ||||
|           </div> | ||||
|           <div class="right"> | ||||
|           <div class="flex-2"> | ||||
|             <div | ||||
|               class="inv-amount" | ||||
|               class="pr-2 mb-2 text-sm not-italic font-normal leading-5 text-black capitalize truncate" | ||||
|             > | ||||
|               {{ payment.user.name }} | ||||
|             </div> | ||||
|  | ||||
|             <div | ||||
|               class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize" | ||||
|             > | ||||
|               {{ payment.payment_number }} | ||||
|             </div> | ||||
|  | ||||
|             <div | ||||
|               class="mb-1 text-xs not-italic font-medium leading-5 text-gray-500 capitalize" | ||||
|             > | ||||
|               {{ payment.invoice_number }} | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <div class="flex-1 whitespace-no-wrap right"> | ||||
|             <div | ||||
|               class="mb-2 text-xl not-italic font-semibold leading-8 text-right text-gray-900" | ||||
|               v-html="$utils.formatMoney(payment.amount, payment.user.currency)" | ||||
|             /> | ||||
|             <div class="inv-date">{{ payment.formattedPaymentDate }}</div> | ||||
|             <!-- <div class="inv-number">{{ payment.payment_method.name }}</div> --> | ||||
|  | ||||
|             <div class="text-sm text-right text-gray-500 non-italic"> | ||||
|               {{ payment.formattedPaymentDate }} | ||||
|             </div> | ||||
|           </div> | ||||
|         </router-link> | ||||
|         <p v-if="!payments.length" class="no-result"> | ||||
|  | ||||
|         <p | ||||
|           v-if="!payments.length" | ||||
|           class="flex justify-center px-4 mt-5 text-sm text-gray-600" | ||||
|         > | ||||
|           {{ $t('payments.no_matching_payments') }} | ||||
|         </p> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="payment-view-page-container"> | ||||
|       <iframe :src="`${shareableLink}`" class="frame-style" /> | ||||
|  | ||||
|     <!-- pdf --> | ||||
|     <div | ||||
|       class="flex flex-col min-h-0 mt-8 overflow-hidden" | ||||
|       style="height: 75vh" | ||||
|     > | ||||
|       <iframe | ||||
|         :src="`${shareableLink}`" | ||||
|         class="flex-1 border border-gray-400 border-solid rounded-md" | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
|   </base-page> | ||||
| </template> | ||||
| <script> | ||||
| import { | ||||
|   DotsHorizontalIcon, | ||||
|   FilterIcon, | ||||
|   SortAscendingIcon, | ||||
|   SortDescendingIcon, | ||||
|   SearchIcon, | ||||
|   LinkIcon, | ||||
|   TrashIcon, | ||||
|   PencilIcon, | ||||
| } from '@vue-hero-icons/solid' | ||||
| import { mapActions, mapGetters } from 'vuex' | ||||
| const _ = require('lodash') | ||||
| export default { | ||||
|   data () { | ||||
|   components: { | ||||
|     DotsHorizontalIcon, | ||||
|     FilterIcon, | ||||
|     SortAscendingIcon, | ||||
|     SortDescendingIcon, | ||||
|     SearchIcon, | ||||
|     TrashIcon, | ||||
|     PencilIcon, | ||||
|     LinkIcon, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       id: null, | ||||
|       count: null, | ||||
| @ -180,82 +229,109 @@ export default { | ||||
|       searchData: { | ||||
|         orderBy: null, | ||||
|         orderByField: null, | ||||
|         searchText: null | ||||
|         searchText: null, | ||||
|       }, | ||||
|       isRequestOnGoing: false, | ||||
|       isSearching: false, | ||||
|       isSendingEmail: false, | ||||
|       isMarkingAsSent: false | ||||
|       isMarkingAsSent: false, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     getOrderBy () { | ||||
|       if (this.searchData.orderBy === 'asc' || this.searchData.orderBy == null) { | ||||
|     pageTitle() { | ||||
|       return this.payment.payment_number | ||||
|     }, | ||||
|     getOrderBy() { | ||||
|       if ( | ||||
|         this.searchData.orderBy === 'asc' || | ||||
|         this.searchData.orderBy == null | ||||
|       ) { | ||||
|         return true | ||||
|       } | ||||
|       return false | ||||
|     }, | ||||
|     getOrderName () { | ||||
|     getOrderName() { | ||||
|       if (this.getOrderBy) { | ||||
|         return this.$t('general.ascending') | ||||
|       } | ||||
|       return this.$t('general.descending') | ||||
|     }, | ||||
|     shareableLink () { | ||||
|     shareableLink() { | ||||
|       return `/payments/pdf/${this.payment.unique_hash}` | ||||
|     } | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     $route (to, from) { | ||||
|     $route(to, from) { | ||||
|       this.loadPayment() | ||||
|     } | ||||
|     }, | ||||
|   }, | ||||
|   created () { | ||||
|  | ||||
|   created() { | ||||
|     this.loadPayments() | ||||
|     this.loadPayment() | ||||
|     this.onSearch = _.debounce(this.onSearch, 500) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     // ...mapActions('invoice', [ | ||||
|     //   'fetchInvoices', | ||||
|     //   'getRecord', | ||||
|     //   'searchInvoice', | ||||
|     //   'markAsSent', | ||||
|     //   'sendEmail', | ||||
|     //   'deleteInvoice', | ||||
|     //   'fetchViewInvoice' | ||||
|     // ]), | ||||
|     ...mapActions('payment', [ | ||||
|       'fetchPayments', | ||||
|       'fetchPayment', | ||||
|       'sendEmail', | ||||
|       'deletePayment', | ||||
|       'searchPayment' | ||||
|       'searchPayment', | ||||
|     ]), | ||||
|     async loadPayments () { | ||||
|       let response = await this.fetchPayments() | ||||
|     ...mapActions('modal', ['openModal']), | ||||
|  | ||||
|     hasActiveUrl(id) { | ||||
|       return this.$route.params.id == id | ||||
|     }, | ||||
|  | ||||
|     async loadPayments() { | ||||
|       let response = await this.fetchPayments({ limit: 'all' }) | ||||
|       if (response.data) { | ||||
|         this.payments = response.data.payments.data | ||||
|       } | ||||
|       setTimeout(() => { | ||||
|         this.scrollToPayment() | ||||
|       }, 500) | ||||
|     }, | ||||
|     async loadPayment () { | ||||
|     scrollToPayment() { | ||||
|       const el = document.getElementById(`payment-${this.$route.params.id}`) | ||||
|  | ||||
|       if (el) { | ||||
|         el.scrollIntoView({ behavior: 'smooth' }) | ||||
|         el.classList.add('shake') | ||||
|       } | ||||
|     }, | ||||
|     async loadPayment() { | ||||
|       let response = await this.fetchPayment(this.$route.params.id) | ||||
|  | ||||
|       if (response.data) { | ||||
|         this.payment = response.data.payment | ||||
|       } | ||||
|     }, | ||||
|     async onSearch () { | ||||
|     async onSearch() { | ||||
|       let data = '' | ||||
|       if (this.searchData.searchText !== '' && this.searchData.searchText !== null && this.searchData.searchText !== undefined) { | ||||
|       if ( | ||||
|         this.searchData.searchText !== '' && | ||||
|         this.searchData.searchText !== null && | ||||
|         this.searchData.searchText !== undefined | ||||
|       ) { | ||||
|         data += `search=${this.searchData.searchText}&` | ||||
|       } | ||||
|  | ||||
|       if (this.searchData.orderBy !== null && this.searchData.orderBy !== undefined) { | ||||
|       if ( | ||||
|         this.searchData.orderBy !== null && | ||||
|         this.searchData.orderBy !== undefined | ||||
|       ) { | ||||
|         data += `orderBy=${this.searchData.orderBy}&` | ||||
|       } | ||||
|  | ||||
|       if (this.searchData.orderByField !== null && this.searchData.orderByField !== undefined) { | ||||
|       if ( | ||||
|         this.searchData.orderByField !== null && | ||||
|         this.searchData.orderByField !== undefined | ||||
|       ) { | ||||
|         data += `orderByField=${this.searchData.orderByField}` | ||||
|       } | ||||
|       this.isSearching = true | ||||
| @ -265,7 +341,7 @@ export default { | ||||
|         this.payments = response.data.payments.data | ||||
|       } | ||||
|     }, | ||||
|     sortData () { | ||||
|     sortData() { | ||||
|       if (this.searchData.orderBy === 'asc') { | ||||
|         this.searchData.orderBy = 'desc' | ||||
|         this.onSearch() | ||||
| @ -275,57 +351,44 @@ export default { | ||||
|       this.onSearch() | ||||
|       return true | ||||
|     }, | ||||
|     async onPaymentSend () { | ||||
|       window.swal({ | ||||
|         title: this.$tc('general.are_you_sure'), | ||||
|         text: this.$tc('payments.confirm_send_payment'), | ||||
|         icon: '/assets/icon/paper-plane-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (value) => { | ||||
|         if (value) { | ||||
|           this.isSendingEmail = true | ||||
|           let response = await this.sendEmail({id: this.payment.id}) | ||||
|           this.isSendingEmail = false | ||||
|           if (response.data.success) { | ||||
|             window.toastr['success'](this.$tc('payments.send_payment_successfully')) | ||||
|             return true | ||||
|           } | ||||
|           if (response.data.error === 'user_email_does_not_exist') { | ||||
|             window.toastr['error'](this.$tc('payments.user_email_does_not_exist')) | ||||
|             return false | ||||
|           } | ||||
|           window.toastr['error'](this.$tc('payments.something_went_wrong')) | ||||
|         } | ||||
|     async onPaymentSend() { | ||||
|       this.openModal({ | ||||
|         title: this.$t('payments.send_payment'), | ||||
|         componentName: 'SendPaymentModal', | ||||
|         id: this.payment.id, | ||||
|         data: this.payment, | ||||
|         variant: 'lg', | ||||
|       }) | ||||
|     }, | ||||
|     copyPdfUrl () { | ||||
|     copyPdfUrl() { | ||||
|       let pdfUrl = `${window.location.origin}/payments/pdf/${this.payment.unique_hash}` | ||||
|  | ||||
|       let response = this.$utils.copyTextToClipboard(pdfUrl) | ||||
|  | ||||
|       window.toastr['success'](this.$tc('Copied PDF url to clipboard!')) | ||||
|       window.toastr['success'](this.$t('general.copied_pdf_url_clipboard')) | ||||
|     }, | ||||
|     async removePayment (id) { | ||||
|     async removePayment(id) { | ||||
|       this.id = id | ||||
|       window.swal({ | ||||
|         title: 'Deleted', | ||||
|         text: 'you will not be able to recover this payment!', | ||||
|         icon: '/assets/icon/trash-solid.svg', | ||||
|         buttons: true, | ||||
|         dangerMode: true | ||||
|       }).then(async (value) => { | ||||
|         if (value) { | ||||
|           let request = await this.deletePayment(this.id) | ||||
|           if (request.data.success) { | ||||
|             window.toastr['success'](this.$tc('payments.deleted_message', 1)) | ||||
|             this.$router.push('/admin/payments') | ||||
|           } else if (request.data.error) { | ||||
|             window.toastr['error'](request.data.message) | ||||
|       window | ||||
|         .swal({ | ||||
|           title: this.$t('general.are_you_sure'), | ||||
|           text: 'you will not be able to recover this payment!', | ||||
|           icon: '/assets/icon/trash-solid.svg', | ||||
|           buttons: true, | ||||
|           dangerMode: true, | ||||
|         }) | ||||
|         .then(async (value) => { | ||||
|           if (value) { | ||||
|             let request = await this.deletePayment({ ids: [id] }) | ||||
|             if (request.data.success) { | ||||
|               window.toastr['success'](this.$tc('payments.deleted_message', 1)) | ||||
|               this.$router.push('/admin/payments') | ||||
|             } else if (request.data.error) { | ||||
|               window.toastr['error'](request.data.message) | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
|         }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user