mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-11-03 22:13:18 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			315 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			315 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
<template>
 | 
						|
  <SelectTemplateModal />
 | 
						|
  <ItemModal />
 | 
						|
  <TaxTypeModal />
 | 
						|
  <BasePage class="relative invoice-create-page">
 | 
						|
    <form @submit.prevent="submitForm">
 | 
						|
      <BasePageHeader :title="pageTitle">
 | 
						|
        <BaseBreadcrumb>
 | 
						|
          <BaseBreadcrumbItem
 | 
						|
            :title="$t('general.home')"
 | 
						|
            to="/admin/dashboard"
 | 
						|
          />
 | 
						|
          <BaseBreadcrumbItem
 | 
						|
            :title="$t('recurring_invoices.title', 2)"
 | 
						|
            to="/admin/recurring-invoices"
 | 
						|
          />
 | 
						|
          <BaseBreadcrumbItem
 | 
						|
            v-if="$route.name === 'invoices.edit'"
 | 
						|
            :title="$t('recurring_invoices.edit_invoice')"
 | 
						|
            to="#"
 | 
						|
            active
 | 
						|
          />
 | 
						|
          <BaseBreadcrumbItem
 | 
						|
            v-else
 | 
						|
            :title="$t('recurring_invoices.new_invoice')"
 | 
						|
            to="#"
 | 
						|
            active
 | 
						|
          />
 | 
						|
        </BaseBreadcrumb>
 | 
						|
 | 
						|
        <template #actions>
 | 
						|
          <router-link
 | 
						|
            :to="`/invoices/pdf/${recurringInvoiceStore.newRecurringInvoice.unique_hash}`"
 | 
						|
          >
 | 
						|
            <BaseButton
 | 
						|
              v-if="$route.name === 'invoices.edit'"
 | 
						|
              target="_blank"
 | 
						|
              class="mr-3"
 | 
						|
              variant="primary-outline"
 | 
						|
              type="button"
 | 
						|
            >
 | 
						|
              <span class="flex">
 | 
						|
                {{ $t('general.view_pdf') }}
 | 
						|
              </span>
 | 
						|
            </BaseButton>
 | 
						|
          </router-link>
 | 
						|
 | 
						|
          <BaseButton
 | 
						|
            :loading="isSaving"
 | 
						|
            :disabled="isSaving"
 | 
						|
            variant="primary"
 | 
						|
            type="submit"
 | 
						|
          >
 | 
						|
            <template #left="slotProps">
 | 
						|
              <BaseIcon
 | 
						|
                v-if="!isSaving"
 | 
						|
                name="SaveIcon"
 | 
						|
                :class="slotProps.class"
 | 
						|
              />
 | 
						|
            </template>
 | 
						|
            {{ $t('recurring_invoices.save_invoice') }}
 | 
						|
          </BaseButton>
 | 
						|
        </template>
 | 
						|
      </BasePageHeader>
 | 
						|
 | 
						|
      <!-- Select Customer & Basic Fields  -->
 | 
						|
      <div class="grid-cols-12 gap-8 mt-6 mb-8 lg:grid">
 | 
						|
        <InvoiceBasicFields
 | 
						|
          :v="v$"
 | 
						|
          :is-loading="isLoadingContent"
 | 
						|
          :is-edit="isEdit"
 | 
						|
        />
 | 
						|
      </div>
 | 
						|
 | 
						|
      <BaseScrollPane>
 | 
						|
        <!-- Invoice Items -->
 | 
						|
        <CreateItems
 | 
						|
          :currency="recurringInvoiceStore.newRecurringInvoice.currency"
 | 
						|
          :is-loading="isLoadingContent"
 | 
						|
          :item-validation-scope="recurringInvoiceValidationScope"
 | 
						|
          :store="recurringInvoiceStore"
 | 
						|
          store-prop="newRecurringInvoice"
 | 
						|
        />
 | 
						|
 | 
						|
        <!-- Invoice Templates -->
 | 
						|
        <div
 | 
						|
          class="
 | 
						|
            block
 | 
						|
            mt-10
 | 
						|
            invoice-foot
 | 
						|
            lg:flex lg:justify-between lg:items-start
 | 
						|
          "
 | 
						|
        >
 | 
						|
          <div class="w-full relative lg:w-1/2">
 | 
						|
            <!-- Invoice Custom Notes -->
 | 
						|
            <NoteFields
 | 
						|
              :store="recurringInvoiceStore"
 | 
						|
              store-prop="newRecurringInvoice"
 | 
						|
              :fields="recurringInvoiceFields"
 | 
						|
              type="Invoice"
 | 
						|
            />
 | 
						|
 | 
						|
            <!-- Invoice Custom Fields -->
 | 
						|
            <InvoiceCustomFields
 | 
						|
              type="Invoice"
 | 
						|
              :is-edit="isEdit"
 | 
						|
              :is-loading="isLoadingContent"
 | 
						|
              :store="recurringInvoiceStore"
 | 
						|
              store-prop="newRecurringInvoice"
 | 
						|
              :custom-field-scope="recurringInvoiceValidationScope"
 | 
						|
              class="mb-6"
 | 
						|
            />
 | 
						|
 | 
						|
            <!-- Invoice Template Button-->
 | 
						|
            <SelectTemplateButton
 | 
						|
              :store="recurringInvoiceStore"
 | 
						|
              store-prop="newRecurringInvoice"
 | 
						|
            />
 | 
						|
          </div>
 | 
						|
 | 
						|
          <!-- Invoice Total Card -->
 | 
						|
          <CreateTotal
 | 
						|
            :currency="recurringInvoiceStore.newRecurringInvoice.currency"
 | 
						|
            :is-loading="isLoadingContent"
 | 
						|
            :store="recurringInvoiceStore"
 | 
						|
            store-prop="newRecurringInvoice"
 | 
						|
            tax-popup-type="invoice"
 | 
						|
          />
 | 
						|
        </div>
 | 
						|
      </BaseScrollPane>
 | 
						|
    </form>
 | 
						|
  </BasePage>
 | 
						|
</template>
 | 
						|
 | 
						|
<script setup>
 | 
						|
import { computed, ref, watch } from 'vue'
 | 
						|
import { useRoute, useRouter } from 'vue-router'
 | 
						|
import { useI18n } from 'vue-i18n'
 | 
						|
import CreateItems from '@/scripts/components/estimate-invoice-common/CreateItems.vue'
 | 
						|
import CreateTotal from '@/scripts/components/estimate-invoice-common/CreateTotal.vue'
 | 
						|
import SelectTemplateButton from '@/scripts/components/estimate-invoice-common/SelectTemplateButton.vue'
 | 
						|
import InvoiceBasicFields from './RecurringInvoiceCreateBasicFields.vue'
 | 
						|
import InvoiceCustomFields from '@/scripts/components/custom-fields/CreateCustomFields.vue'
 | 
						|
import NoteFields from '@/scripts/components/estimate-invoice-common/CreateNotesField.vue'
 | 
						|
 | 
						|
import {
 | 
						|
  required,
 | 
						|
  maxLength,
 | 
						|
  numeric,
 | 
						|
  helpers,
 | 
						|
  requiredIf,
 | 
						|
  decimal,
 | 
						|
} from '@vuelidate/validators'
 | 
						|
 | 
						|
import useVuelidate from '@vuelidate/core'
 | 
						|
import { useCompanyStore } from '@/scripts/stores/company'
 | 
						|
import { useCustomFieldStore } from '@/scripts/stores/custom-field'
 | 
						|
import { useRecurringInvoiceStore } from '@/scripts/stores/recurring-invoice'
 | 
						|
 | 
						|
import SelectTemplateModal from '@/scripts/components/modal-components/SelectTemplateModal.vue'
 | 
						|
import TaxTypeModal from '@/scripts/components/modal-components/TaxTypeModal.vue'
 | 
						|
import ItemModal from '@/scripts/components/modal-components/ItemModal.vue'
 | 
						|
 | 
						|
const recurringInvoiceStore = useRecurringInvoiceStore()
 | 
						|
const companyStore = useCompanyStore()
 | 
						|
const customFieldStore = useCustomFieldStore()
 | 
						|
 | 
						|
const recurringInvoiceValidationScope = 'newRecurringInvoice'
 | 
						|
const { t } = useI18n()
 | 
						|
let isSaving = ref(false)
 | 
						|
 | 
						|
const recurringInvoiceFields = ref([
 | 
						|
  'customer',
 | 
						|
  'company',
 | 
						|
  'customerCustom',
 | 
						|
  'invoice',
 | 
						|
  'invoiceCustom',
 | 
						|
])
 | 
						|
 | 
						|
let route = useRoute()
 | 
						|
let router = useRouter()
 | 
						|
 | 
						|
let isLoadingContent = computed(
 | 
						|
  () =>
 | 
						|
    recurringInvoiceStore.isFetchingInvoice ||
 | 
						|
    recurringInvoiceStore.isFetchingInitialSettings
 | 
						|
)
 | 
						|
 | 
						|
let pageTitle = computed(() =>
 | 
						|
  isEdit.value
 | 
						|
    ? t('recurring_invoices.edit_invoice')
 | 
						|
    : t('recurring_invoices.new_invoice')
 | 
						|
)
 | 
						|
 | 
						|
let isEdit = computed(() => route.name === 'recurring-invoices.edit')
 | 
						|
 | 
						|
const rules = {
 | 
						|
  starts_at: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  status: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  frequency: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  limit_by: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  limit_date: {
 | 
						|
    required: helpers.withMessage(
 | 
						|
      t('validation.required'),
 | 
						|
      requiredIf(function () {
 | 
						|
        return recurringInvoiceStore.newRecurringInvoice.limit_by === 'DATE'
 | 
						|
      })
 | 
						|
    ),
 | 
						|
  },
 | 
						|
  limit_count: {
 | 
						|
    required: helpers.withMessage(
 | 
						|
      t('validation.required'),
 | 
						|
      requiredIf(function () {
 | 
						|
        return recurringInvoiceStore.newRecurringInvoice.limit_by === 'COUNT'
 | 
						|
      })
 | 
						|
    ),
 | 
						|
  },
 | 
						|
  selectedFrequency: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  customer_id: {
 | 
						|
    required: helpers.withMessage(t('validation.required'), required),
 | 
						|
  },
 | 
						|
  exchange_rate: {
 | 
						|
    required: requiredIf(function () {
 | 
						|
      helpers.withMessage(t('validation.required'), required)
 | 
						|
      return recurringInvoiceStore.showExchangeRate
 | 
						|
    }),
 | 
						|
    decimal: helpers.withMessage(t('validation.valid_exchange_rate'), decimal),
 | 
						|
  },
 | 
						|
}
 | 
						|
 | 
						|
const v$ = useVuelidate(
 | 
						|
  rules,
 | 
						|
  computed(() => recurringInvoiceStore.newRecurringInvoice),
 | 
						|
  { $scope: recurringInvoiceValidationScope }
 | 
						|
)
 | 
						|
 | 
						|
recurringInvoiceStore.resetCurrentRecurringInvoice()
 | 
						|
recurringInvoiceStore.fetchRecurringInvoiceInitialSettings(isEdit.value)
 | 
						|
customFieldStore.resetCustomFields()
 | 
						|
v$.value.$reset
 | 
						|
 | 
						|
watch(
 | 
						|
  () => recurringInvoiceStore.newRecurringInvoice.customer,
 | 
						|
  (newVal) => {
 | 
						|
    if (newVal && newVal.currency) {
 | 
						|
      recurringInvoiceStore.newRecurringInvoice.currency = newVal.currency
 | 
						|
    } else {
 | 
						|
      recurringInvoiceStore.newRecurringInvoice.currency =
 | 
						|
        companyStore.selectedCompanyCurrency
 | 
						|
    }
 | 
						|
  }
 | 
						|
)
 | 
						|
 | 
						|
async function submitForm() {
 | 
						|
  v$.value.$touch()
 | 
						|
 | 
						|
  if (v$.value.$invalid) {
 | 
						|
    return false
 | 
						|
  }
 | 
						|
 | 
						|
  isSaving.value = true
 | 
						|
 | 
						|
  let data = {
 | 
						|
    ...recurringInvoiceStore.newRecurringInvoice,
 | 
						|
    sub_total: recurringInvoiceStore.getSubTotal,
 | 
						|
    total: recurringInvoiceStore.getTotal,
 | 
						|
    tax: recurringInvoiceStore.getTotalTax,
 | 
						|
  }
 | 
						|
 | 
						|
  if (route.params.id) {
 | 
						|
    recurringInvoiceStore
 | 
						|
      .updateRecurringInvoice(data)
 | 
						|
      .then((res) => {
 | 
						|
        if (res.data.data) {
 | 
						|
          router.push(`/admin/recurring-invoices/${res.data.data.id}/view`)
 | 
						|
        }
 | 
						|
        isSaving.value = false
 | 
						|
      })
 | 
						|
      .catch((err) => {
 | 
						|
        isSaving.value = false
 | 
						|
      })
 | 
						|
  } else {
 | 
						|
    submitCreate(data)
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
function submitCreate(data) {
 | 
						|
  recurringInvoiceStore
 | 
						|
    .addRecurringInvoice(data)
 | 
						|
    .then((res) => {
 | 
						|
      if (res.data.data) {
 | 
						|
        router.push(`/admin/recurring-invoices/${res.data.data.id}/view`)
 | 
						|
      }
 | 
						|
      isSaving.value = false
 | 
						|
    })
 | 
						|
    .catch((err) => {
 | 
						|
      isSaving.value = false
 | 
						|
    })
 | 
						|
}
 | 
						|
 | 
						|
function checkValid() {
 | 
						|
  return false
 | 
						|
}
 | 
						|
</script>
 |