mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-10-30 21:21:09 -04:00 
			
		
		
		
	v5.0.0 update
This commit is contained in:
		| @ -0,0 +1,71 @@ | ||||
| <template> | ||||
|   <InvoicesTabInvoiceNumber /> | ||||
|  | ||||
|   <BaseDivider class="my-8" /> | ||||
|  | ||||
|   <InvoicesTabDueDate /> | ||||
|  | ||||
|   <BaseDivider class="my-8" /> | ||||
|  | ||||
|   <InvoicesTabRetrospective /> | ||||
|  | ||||
|   <BaseDivider class="my-8" /> | ||||
|  | ||||
|   <InvoicesTabDefaultFormats /> | ||||
|  | ||||
|   <BaseDivider class="mt-6 mb-2" /> | ||||
|  | ||||
|   <ul class="divide-y divide-gray-200"> | ||||
|     <BaseSwitchSection | ||||
|       v-model="sendAsAttachmentField" | ||||
|       :title="$t('settings.customization.invoices.invoice_email_attachment')" | ||||
|       :description=" | ||||
|         $t( | ||||
|           'settings.customization.invoices.invoice_email_attachment_setting_description' | ||||
|         ) | ||||
|       " | ||||
|     /> | ||||
|   </ul> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { computed, reactive, inject } from 'vue' | ||||
| import { useCompanyStore } from '@/scripts/stores/company' | ||||
| import InvoicesTabInvoiceNumber from './InvoicesTabInvoiceNumber.vue' | ||||
| import InvoicesTabRetrospective from './InvoicesTabRetrospective.vue' | ||||
| import InvoicesTabDueDate from './InvoicesTabDueDate.vue' | ||||
| import InvoicesTabDefaultFormats from './InvoicesTabDefaultFormats.vue' | ||||
|  | ||||
| const utils = inject('utils') | ||||
| const companyStore = useCompanyStore() | ||||
|  | ||||
| const invoiceSettings = reactive({ | ||||
|   invoice_email_attachment: null, | ||||
| }) | ||||
|  | ||||
| utils.mergeSettings(invoiceSettings, { | ||||
|   ...companyStore.selectedCompanySettings, | ||||
| }) | ||||
|  | ||||
| const sendAsAttachmentField = computed({ | ||||
|   get: () => { | ||||
|     return invoiceSettings.invoice_email_attachment === 'YES' | ||||
|   }, | ||||
|   set: async (newValue) => { | ||||
|     const value = newValue ? 'YES' : 'NO' | ||||
|  | ||||
|     let data = { | ||||
|       settings: { | ||||
|         invoice_email_attachment: value, | ||||
|       }, | ||||
|     } | ||||
|  | ||||
|     invoiceSettings.invoice_email_attachment = value | ||||
|  | ||||
|     await companyStore.updateCompanySettings({ | ||||
|       data, | ||||
|       message: 'general.setting_updated', | ||||
|     }) | ||||
|   }, | ||||
| }) | ||||
| </script> | ||||
| @ -0,0 +1,127 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitForm"> | ||||
|     <h6 class="text-gray-900 text-lg font-medium"> | ||||
|       {{ $t('settings.customization.invoices.default_formats') }} | ||||
|     </h6> | ||||
|     <p class="mt-1 text-sm text-gray-500 mb-2"> | ||||
|       {{ $t('settings.customization.invoices.default_formats_description') }} | ||||
|     </p> | ||||
|  | ||||
|     <BaseInputGroup | ||||
|       :label="$t('settings.customization.invoices.default_invoice_email_body')" | ||||
|       class="mt-6 mb-4" | ||||
|     > | ||||
|       <BaseCustomInput | ||||
|         v-model="formatSettings.invoice_mail_body" | ||||
|         :fields="invoiceMailFields" | ||||
|       /> | ||||
|     </BaseInputGroup> | ||||
|  | ||||
|     <BaseInputGroup | ||||
|       :label="$t('settings.customization.invoices.company_address_format')" | ||||
|       class="mt-6 mb-4" | ||||
|     > | ||||
|       <BaseCustomInput | ||||
|         v-model="formatSettings.invoice_company_address_format" | ||||
|         :fields="companyFields" | ||||
|       /> | ||||
|     </BaseInputGroup> | ||||
|  | ||||
|     <BaseInputGroup | ||||
|       :label="$t('settings.customization.invoices.shipping_address_format')" | ||||
|       class="mt-6 mb-4" | ||||
|     > | ||||
|       <BaseCustomInput | ||||
|         v-model="formatSettings.invoice_shipping_address_format" | ||||
|         :fields="shippingFields" | ||||
|       /> | ||||
|     </BaseInputGroup> | ||||
|  | ||||
|     <BaseInputGroup | ||||
|       :label="$t('settings.customization.invoices.billing_address_format')" | ||||
|       class="mt-6 mb-4" | ||||
|     > | ||||
|       <BaseCustomInput | ||||
|         v-model="formatSettings.invoice_billing_address_format" | ||||
|         :fields="billingFields" | ||||
|       /> | ||||
|     </BaseInputGroup> | ||||
|  | ||||
|     <BaseButton | ||||
|       :loading="isSaving" | ||||
|       :disabled="isSaving" | ||||
|       variant="primary" | ||||
|       type="submit" | ||||
|       class="mt-4" | ||||
|     > | ||||
|       <template #left="slotProps"> | ||||
|         <BaseIcon v-if="!isSaving" :class="slotProps.class" name="SaveIcon" /> | ||||
|       </template> | ||||
|       {{ $t('settings.customization.save') }} | ||||
|     </BaseButton> | ||||
|   </form> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { ref, reactive, inject } from 'vue' | ||||
| import { useCompanyStore } from '@/scripts/stores/company' | ||||
|  | ||||
| const companyStore = useCompanyStore() | ||||
| const utils = inject('utils') | ||||
|  | ||||
| const invoiceMailFields = ref([ | ||||
|   'customer', | ||||
|   'customerCustom', | ||||
|   'invoice', | ||||
|   'invoiceCustom', | ||||
|   'company', | ||||
| ]) | ||||
|  | ||||
| const billingFields = ref([ | ||||
|   'billing', | ||||
|   'customer', | ||||
|   'customerCustom', | ||||
|   'invoiceCustom', | ||||
| ]) | ||||
|  | ||||
| const shippingFields = ref([ | ||||
|   'shipping', | ||||
|   'customer', | ||||
|   'customerCustom', | ||||
|   'invoiceCustom', | ||||
| ]) | ||||
|  | ||||
| const companyFields = ref(['company', 'invoiceCustom']) | ||||
|  | ||||
| let isSaving = ref(false) | ||||
|  | ||||
| const formatSettings = reactive({ | ||||
|   invoice_mail_body: null, | ||||
|   invoice_company_address_format: null, | ||||
|   invoice_shipping_address_format: null, | ||||
|   invoice_billing_address_format: null, | ||||
| }) | ||||
|  | ||||
| utils.mergeSettings(formatSettings, { | ||||
|   ...companyStore.selectedCompanySettings, | ||||
| }) | ||||
|  | ||||
| async function submitForm() { | ||||
|   isSaving.value = true | ||||
|  | ||||
|   let data = { | ||||
|     settings: { | ||||
|       ...formatSettings, | ||||
|     }, | ||||
|   } | ||||
|  | ||||
|   await companyStore.updateCompanySettings({ | ||||
|     data, | ||||
|     message: 'settings.customization.invoices.invoice_settings_updated', | ||||
|   }) | ||||
|  | ||||
|   isSaving.value = false | ||||
|  | ||||
|   return true | ||||
| } | ||||
| </script> | ||||
| @ -0,0 +1,135 @@ | ||||
| <template> | ||||
|   <form @submit.prevent="submitForm"> | ||||
|     <h6 class="text-gray-900 text-lg font-medium"> | ||||
|       {{ $t('settings.customization.invoices.due_date') }} | ||||
|     </h6> | ||||
|     <p class="mt-1 text-sm text-gray-500 mb-2"> | ||||
|       {{ $t('settings.customization.invoices.due_date_description') }} | ||||
|     </p> | ||||
|  | ||||
|     <BaseSwitchSection | ||||
|       v-model="dueDateAutoField" | ||||
|       :title="$t('settings.customization.invoices.set_due_date_automatically')" | ||||
|       :description=" | ||||
|         $t( | ||||
|           'settings.customization.invoices.set_due_date_automatically_description' | ||||
|         ) | ||||
|       " | ||||
|     /> | ||||
|  | ||||
|     <BaseInputGroup | ||||
|       v-if="dueDateAutoField" | ||||
|       :label="$t('settings.customization.invoices.due_date_days')" | ||||
|       :error=" | ||||
|         v$.dueDateSettings.invoice_due_date_days.$error && | ||||
|         v$.dueDateSettings.invoice_due_date_days.$errors[0].$message | ||||
|       " | ||||
|       class="mt-2 mb-4" | ||||
|     > | ||||
|       <div class="w-full sm:w-1/2 md:w-1/4 lg:w-1/5"> | ||||
|         <BaseInput | ||||
|           v-model="dueDateSettings.invoice_due_date_days" | ||||
|           :invalid="v$.dueDateSettings.invoice_due_date_days.$error" | ||||
|           type="number" | ||||
|           @input="v$.dueDateSettings.invoice_due_date_days.$touch()" | ||||
|         /> | ||||
|       </div> | ||||
|     </BaseInputGroup> | ||||
|  | ||||
|     <BaseButton | ||||
|       :loading="isSaving" | ||||
|       :disabled="isSaving" | ||||
|       variant="primary" | ||||
|       type="submit" | ||||
|       class="mt-4" | ||||
|     > | ||||
|       <template #left="slotProps"> | ||||
|         <BaseIcon v-if="!isSaving" :class="slotProps.class" name="SaveIcon" /> | ||||
|       </template> | ||||
|       {{ $t('settings.customization.save') }} | ||||
|     </BaseButton> | ||||
|   </form> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { ref, computed, onMounted, reactive, inject } from 'vue' | ||||
| import { useI18n } from 'vue-i18n' | ||||
| import { useCompanyStore } from '@/scripts/stores/company' | ||||
| import { numeric, helpers, requiredIf } from '@vuelidate/validators' | ||||
|  | ||||
| import useVuelidate from '@vuelidate/core' | ||||
|  | ||||
| const { t } = useI18n() | ||||
| const companyStore = useCompanyStore() | ||||
|  | ||||
| const utils = inject('utils') | ||||
|  | ||||
| let isSaving = ref(false) | ||||
|  | ||||
| const dueDateSettings = reactive({ | ||||
|   invoice_set_due_date_automatically: null, | ||||
|   invoice_due_date_days: null, | ||||
| }) | ||||
|  | ||||
| utils.mergeSettings(dueDateSettings, { | ||||
|   ...companyStore.selectedCompanySettings, | ||||
| }) | ||||
|  | ||||
| const dueDateAutoField = computed({ | ||||
|   get: () => { | ||||
|     return dueDateSettings.invoice_set_due_date_automatically === 'YES' | ||||
|   }, | ||||
|   set: async (newValue) => { | ||||
|     const value = newValue ? 'YES' : 'NO' | ||||
|  | ||||
|     dueDateSettings.invoice_set_due_date_automatically = value | ||||
|   }, | ||||
| }) | ||||
|  | ||||
| const rules = computed(() => { | ||||
|   return { | ||||
|     dueDateSettings: { | ||||
|       invoice_due_date_days: { | ||||
|         required: helpers.withMessage( | ||||
|           t('validation.required'), | ||||
|           requiredIf(dueDateAutoField.value) | ||||
|         ), | ||||
|         numeric: helpers.withMessage(t('validation.numbers_only'), numeric), | ||||
|       }, | ||||
|     }, | ||||
|   } | ||||
| }) | ||||
|  | ||||
| const v$ = useVuelidate(rules, { dueDateSettings }) | ||||
|  | ||||
| async function submitForm() { | ||||
|   v$.value.dueDateSettings.$touch() | ||||
|  | ||||
|   if (v$.value.dueDateSettings.$invalid) { | ||||
|     return false | ||||
|   } | ||||
|  | ||||
|   isSaving.value = true | ||||
|  | ||||
|   let data = { | ||||
|     settings: { | ||||
|       ...dueDateSettings, | ||||
|     }, | ||||
|   } | ||||
|   // Don't pass due_date_days if setting is not enabled | ||||
|    | ||||
|   if (!dueDateAutoField.value) { | ||||
|     delete data.settings.invoice_due_date_days | ||||
|   } | ||||
|  | ||||
|   await companyStore.updateCompanySettings({ | ||||
|     data, | ||||
|     message: 'settings.customization.invoices.invoice_settings_updated', | ||||
|   }) | ||||
|  | ||||
|   isSaving.value = false | ||||
|  | ||||
|   return true | ||||
| } | ||||
| </script> | ||||
|  | ||||
| @ -0,0 +1,15 @@ | ||||
| <template> | ||||
|   <NumberCustomizer | ||||
|     type="invoice" | ||||
|     :type-store="invoiceStore" | ||||
|     default-series="INV" | ||||
|   /> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { useInvoiceStore } from '@/scripts/stores/invoice' | ||||
| import NumberCustomizer from '../NumberCustomizer.vue' | ||||
|  | ||||
| const invoiceStore = useInvoiceStore() | ||||
| </script> | ||||
|  | ||||
| @ -0,0 +1,93 @@ | ||||
| <template> | ||||
|   <h6 class="text-gray-900 text-lg font-medium"> | ||||
|     {{ $tc('settings.customization.invoices.retrospective_edits') }} | ||||
|   </h6> | ||||
|   <p class="mt-1 text-sm text-gray-500"> | ||||
|     {{ $t('settings.customization.invoices.retrospective_edits_description') }} | ||||
|   </p> | ||||
|  | ||||
|   <BaseInputGroup required> | ||||
|     <BaseRadio | ||||
|       id="allow" | ||||
|       v-model="settingsForm.retrospective_edits" | ||||
|       :label="$t('settings.customization.invoices.allow')" | ||||
|       size="sm" | ||||
|       name="filter" | ||||
|       value="allow" | ||||
|       class="mt-2" | ||||
|       @update:modelValue="submitForm" | ||||
|     /> | ||||
|  | ||||
|     <BaseRadio | ||||
|       id="disable_on_invoice_partial_paid" | ||||
|       v-model="settingsForm.retrospective_edits" | ||||
|       :label=" | ||||
|         $t('settings.customization.invoices.disable_on_invoice_partial_paid') | ||||
|       " | ||||
|       size="sm" | ||||
|       name="filter" | ||||
|       value="disable_on_invoice_partial_paid" | ||||
|       class="mt-2" | ||||
|       @update:modelValue="submitForm" | ||||
|     /> | ||||
|     <BaseRadio | ||||
|       id="disable_on_invoice_paid" | ||||
|       v-model="settingsForm.retrospective_edits" | ||||
|       :label="$t('settings.customization.invoices.disable_on_invoice_paid')" | ||||
|       size="sm" | ||||
|       name="filter" | ||||
|       value="disable_on_invoice_paid" | ||||
|       class="my-2" | ||||
|       @update:modelValue="submitForm" | ||||
|     /> | ||||
|     <BaseRadio | ||||
|       id="disable_on_invoice_sent" | ||||
|       v-model="settingsForm.retrospective_edits" | ||||
|       :label="$t('settings.customization.invoices.disable_on_invoice_sent')" | ||||
|       size="sm" | ||||
|       name="filter" | ||||
|       value="disable_on_invoice_sent" | ||||
|       @update:modelValue="submitForm" | ||||
|     /> | ||||
|   </BaseInputGroup> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| import { reactive, computed, ref, inject } from 'vue' | ||||
| import { useCompanyStore } from '@/scripts/stores/company' | ||||
| import { useI18n } from 'vue-i18n' | ||||
| import { useGlobalStore } from '@/scripts/stores/global' | ||||
|  | ||||
| const { t, tm } = useI18n() | ||||
| const companyStore = useCompanyStore() | ||||
| const globalStore = useGlobalStore() | ||||
| const utils = inject('utils') | ||||
|  | ||||
| const settingsForm = reactive({ retrospective_edits: null }) | ||||
|  | ||||
| utils.mergeSettings(settingsForm, { | ||||
|   ...companyStore.selectedCompanySettings, | ||||
| }) | ||||
|  | ||||
| const retrospectiveEditOptions = computed(() => { | ||||
|   return globalStore.config.retrospective_edits.map((option) => { | ||||
|     option.title = t(option.key) | ||||
|     return option | ||||
|   }) | ||||
| }) | ||||
|  | ||||
| async function submitForm() { | ||||
|   let data = { | ||||
|     settings: { | ||||
|       ...settingsForm, | ||||
|     }, | ||||
|   } | ||||
|  | ||||
|   await companyStore.updateCompanySettings({ | ||||
|     data, | ||||
|     message: 'settings.customization.invoices.invoice_settings_updated', | ||||
|   }) | ||||
|  | ||||
|   return true | ||||
| } | ||||
| </script> | ||||
		Reference in New Issue
	
	Block a user