mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-27 11:41:09 -04:00
Merge branch 'master' of gitlab.com:mohit.panjvani/crater-web into fix_all_customer_load
This commit is contained in:
@ -31,6 +31,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
isMarkAsDefault: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
})
|
||||
|
||||
const modalStore = useModalStore()
|
||||
@ -38,6 +42,17 @@ const modalStore = useModalStore()
|
||||
const { t } = useI18n()
|
||||
|
||||
function openTemplateModal() {
|
||||
let markAsDefaultDescription = ''
|
||||
if (props.storeProp == 'newEstimate') {
|
||||
markAsDefaultDescription = t(
|
||||
'estimates.mark_as_default_estimate_template_description'
|
||||
)
|
||||
} else if (props.storeProp == 'newInvoice') {
|
||||
markAsDefaultDescription = t(
|
||||
'invoices.mark_as_default_invoice_template_description'
|
||||
)
|
||||
}
|
||||
|
||||
modalStore.openModal({
|
||||
title: t('general.choose_template'),
|
||||
componentName: 'SelectTemplate',
|
||||
@ -45,6 +60,8 @@ function openTemplateModal() {
|
||||
templates: props.store.templates,
|
||||
store: props.store,
|
||||
storeProp: props.storeProp,
|
||||
isMarkAsDefault: props.isMarkAsDefault,
|
||||
markAsDefaultDescription,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -30,12 +30,12 @@
|
||||
cursor-pointer
|
||||
hover:border-primary-300
|
||||
"
|
||||
@click="selectedTemplate = template.name"
|
||||
>
|
||||
<img
|
||||
:src="template.path"
|
||||
:alt="template.name"
|
||||
class="w-full"
|
||||
@click="selectedTemplate = template.name"
|
||||
class="w-full min-h-[100px]"
|
||||
/>
|
||||
<img
|
||||
v-if="selectedTemplate === template.name"
|
||||
@ -58,7 +58,18 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="!modalStore.data.store.isEdit" class="z-0 flex ml-3 pt-5">
|
||||
<BaseCheckbox
|
||||
v-model="modalStore.data.isMarkAsDefault"
|
||||
:set-initial-value="false"
|
||||
variant="primary"
|
||||
:label="$t('general.mark_as_default')"
|
||||
:description="modalStore.data.markAsDefaultDescription"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid">
|
||||
<BaseButton class="mr-3" variant="primary-outline" @click="closeModal">
|
||||
{{ $t('general.cancel') }}
|
||||
@ -76,8 +87,10 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { useModalStore } from '@/scripts/stores/modal'
|
||||
import { useUserStore } from '@/scripts/admin/stores/user'
|
||||
|
||||
const modalStore = useModalStore()
|
||||
const userStore = useUserStore()
|
||||
|
||||
const selectedTemplate = ref('')
|
||||
|
||||
@ -100,6 +113,22 @@ function setData() {
|
||||
|
||||
async function chooseTemplate() {
|
||||
await modalStore.data.store.setTemplate(selectedTemplate.value)
|
||||
// update default estimate or invoice template
|
||||
if (!modalStore.data.store.isEdit && modalStore.data.isMarkAsDefault) {
|
||||
if (modalStore.data.storeProp == 'newEstimate') {
|
||||
await userStore.updateUserSettings({
|
||||
settings: {
|
||||
default_estimate_template: selectedTemplate.value,
|
||||
},
|
||||
})
|
||||
} else if (modalStore.data.storeProp == 'newInvoice') {
|
||||
await userStore.updateUserSettings({
|
||||
settings: {
|
||||
default_invoice_template: selectedTemplate.value,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
closeModal()
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import { handleError } from '@/scripts/helpers/error-handling'
|
||||
import estimateStub from '../stub/estimate'
|
||||
import estimateItemStub from '../stub/estimate-item'
|
||||
import taxStub from '../stub/tax'
|
||||
import { useUserStore } from './user'
|
||||
|
||||
export const useEstimateStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -497,6 +498,7 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
const itemStore = useItemStore()
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
|
||||
this.isFetchingInitialSettings = true
|
||||
this.newEstimate.selectedCurrency = companyStore.selectedCompanyCurrency
|
||||
@ -546,6 +548,9 @@ export const useEstimateStore = (useWindow = false) => {
|
||||
}
|
||||
|
||||
this.setTemplate(this.templates[0].name)
|
||||
this.newEstimate.template_name =
|
||||
userStore.currentUserSettings.default_estimate_template ?
|
||||
userStore.currentUserSettings.default_estimate_template : this.newEstimate.template_name
|
||||
}
|
||||
|
||||
if (isEdit) {
|
||||
|
||||
@ -61,15 +61,15 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
Object.assign(this.currentExpense, response.data.data)
|
||||
this.currentExpense.selectedCurrency =
|
||||
response.data.data.currency
|
||||
|
||||
if (response.data.data.attachment_receipt) {
|
||||
this.currentExpense.attachment_receipt = null
|
||||
if (response.data.data.attachment_receipt_url) {
|
||||
if (
|
||||
utils.isImageFile(
|
||||
response.data.data.attachment_receipt_meta.mime_type
|
||||
)
|
||||
) {
|
||||
this.currentExpense.receiptFiles = [
|
||||
{ image: `/expenses/${id}/receipt` },
|
||||
{ image: `/reports/expenses/${id}/receipt?${response.data.data.attachment_receipt_meta.uuid}` },
|
||||
]
|
||||
} else {
|
||||
this.currentExpense.receiptFiles = [
|
||||
@ -118,12 +118,13 @@ export const useExpenseStore = (useWindow = false) => {
|
||||
})
|
||||
},
|
||||
|
||||
updateExpense({ id, data }) {
|
||||
updateExpense({ id, data, isAttachmentReceiptRemoved }) {
|
||||
const notificationStore = useNotificationStore()
|
||||
|
||||
const formData = utils.toFormData(data)
|
||||
|
||||
formData.append('_method', 'PUT')
|
||||
formData.append('is_attachment_receipt_removed', isAttachmentReceiptRemoved)
|
||||
|
||||
return new Promise((resolve) => {
|
||||
axios.post(`/api/v1/expenses/${id}`, formData).then((response) => {
|
||||
|
||||
@ -14,6 +14,7 @@ import { useCustomerStore } from './customer'
|
||||
import { useTaxTypeStore } from './tax-type'
|
||||
import { useCompanyStore } from './company'
|
||||
import { useItemStore } from './item'
|
||||
import { useUserStore } from './user'
|
||||
|
||||
export const useInvoiceStore = (useWindow = false) => {
|
||||
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||
@ -445,6 +446,7 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
const itemStore = useItemStore()
|
||||
const taxTypeStore = useTaxTypeStore()
|
||||
const route = useRoute()
|
||||
const userStore = useUserStore()
|
||||
|
||||
this.isFetchingInitialSettings = true
|
||||
|
||||
@ -495,6 +497,9 @@ export const useInvoiceStore = (useWindow = false) => {
|
||||
|
||||
if (res3.data) {
|
||||
this.setTemplate(this.templates[0].name)
|
||||
this.newInvoice.template_name =
|
||||
userStore.currentUserSettings.default_invoice_template ?
|
||||
userStore.currentUserSettings.default_invoice_template : this.newInvoice.template_name
|
||||
}
|
||||
}
|
||||
if (isEdit) {
|
||||
|
||||
@ -108,6 +108,14 @@ export const useUserStore = (useWindow = false) => {
|
||||
this.currentUserSettings.language = data.settings.language
|
||||
global.locale = data.settings.language
|
||||
}
|
||||
if (data.settings.default_estimate_template) {
|
||||
this.currentUserSettings.default_estimate_template =
|
||||
data.settings.default_estimate_template
|
||||
}
|
||||
if (data.settings.default_invoice_template) {
|
||||
this.currentUserSettings.default_invoice_template =
|
||||
data.settings.default_invoice_template
|
||||
}
|
||||
resolve(response)
|
||||
})
|
||||
.catch((err) => {
|
||||
|
||||
@ -119,6 +119,7 @@
|
||||
:store="estimateStore"
|
||||
component-name="EstimateTemplate"
|
||||
store-prop="newEstimate"
|
||||
:is-mark-as-default="isMarkAsDefault"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -171,6 +172,7 @@ const { t } = useI18n()
|
||||
|
||||
const estimateValidationScope = 'newEstimate'
|
||||
let isSaving = ref(false)
|
||||
const isMarkAsDefault = ref(false)
|
||||
|
||||
const estimateNoteFieldList = ref([
|
||||
'customer',
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
|
||||
<template #actions>
|
||||
<BaseButton
|
||||
v-if="isEdit && expenseStore.currentExpense.attachment_receipt"
|
||||
v-if="isEdit && expenseStore.currentExpense.attachment_receipt_url"
|
||||
:href="receiptDownloadUrl"
|
||||
tag="a"
|
||||
variant="primary-outline"
|
||||
@ -319,6 +319,7 @@ const globalStore = useGlobalStore()
|
||||
let isSaving = ref(false)
|
||||
let isFetchingInitialData = ref(false)
|
||||
const expenseValidationScope = 'newExpense'
|
||||
const isAttachmentReceiptRemoved = ref(false)
|
||||
|
||||
const rules = computed(() => {
|
||||
return {
|
||||
@ -383,7 +384,7 @@ const pageTitle = computed(() =>
|
||||
)
|
||||
|
||||
const receiptDownloadUrl = computed(() =>
|
||||
isEdit.value ? `/expenses/${route.params.id}/download-receipt` : ''
|
||||
isEdit.value ? `/reports/expenses/${route.params.id}/download-receipt` : ''
|
||||
)
|
||||
|
||||
expenseStore.resetCurrentExpenseData()
|
||||
@ -397,6 +398,7 @@ function onFileInputChange(fileName, file) {
|
||||
|
||||
function onFileInputRemove() {
|
||||
expenseStore.currentExpense.attachment_receipt = null
|
||||
isAttachmentReceiptRemoved.value = true
|
||||
}
|
||||
|
||||
function openCategoryModal() {
|
||||
@ -487,11 +489,14 @@ async function submitForm() {
|
||||
await expenseStore.updateExpense({
|
||||
id: route.params.id,
|
||||
data: formData,
|
||||
isAttachmentReceiptRemoved: isAttachmentReceiptRemoved.value
|
||||
})
|
||||
} else {
|
||||
await expenseStore.addExpense(formData)
|
||||
}
|
||||
isSaving.value = false
|
||||
expenseStore.currentExpense.attachment_receipt = null
|
||||
isAttachmentReceiptRemoved.value = false
|
||||
router.push('/admin/expenses')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
||||
@ -118,6 +118,7 @@
|
||||
:store="invoiceStore"
|
||||
store-prop="newInvoice"
|
||||
component-name="InvoiceTemplate"
|
||||
:is-mark-as-default="isMarkAsDefault"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -173,6 +174,7 @@ let router = useRouter()
|
||||
|
||||
const invoiceValidationScope = 'newInvoice'
|
||||
let isSaving = ref(false)
|
||||
const isMarkAsDefault = ref(false)
|
||||
|
||||
const invoiceNoteFieldList = ref([
|
||||
'customer',
|
||||
|
||||
@ -118,6 +118,7 @@ const { t } = useI18n()
|
||||
let isSaving = ref(false)
|
||||
let avatarFileBlob = ref(null)
|
||||
let imgFiles = ref([])
|
||||
const isAdminAvatarRemoved = ref(false)
|
||||
|
||||
if (userStore.currentUser.avatar) {
|
||||
imgFiles.value.push({
|
||||
@ -170,6 +171,7 @@ function onFileInputChange(fileName, file) {
|
||||
|
||||
function onFileInputRemove() {
|
||||
avatarFileBlob.value = null
|
||||
isAdminAvatarRemoved.value = true
|
||||
}
|
||||
|
||||
async function updateUserData() {
|
||||
@ -209,12 +211,17 @@ async function updateUserData() {
|
||||
if (response.data.data) {
|
||||
isSaving.value = false
|
||||
|
||||
if (avatarFileBlob.value) {
|
||||
if (avatarFileBlob.value || isAdminAvatarRemoved.value) {
|
||||
let avatarData = new FormData()
|
||||
|
||||
avatarData.append('admin_avatar', avatarFileBlob.value)
|
||||
if (avatarFileBlob.value) {
|
||||
avatarData.append('admin_avatar', avatarFileBlob.value)
|
||||
}
|
||||
avatarData.append('is_admin_avatar_removed', isAdminAvatarRemoved.value)
|
||||
|
||||
await userStore.uploadAvatar(avatarData)
|
||||
avatarFileBlob.value = null
|
||||
isAdminAvatarRemoved.value = false
|
||||
}
|
||||
|
||||
userForm.password = ''
|
||||
|
||||
@ -180,6 +180,7 @@ utils.mergeSettings(companyForm, {
|
||||
let previewLogo = ref([])
|
||||
let logoFileBlob = ref(null)
|
||||
let logoFileName = ref(null)
|
||||
const isCompanyLogoRemoved = ref(false)
|
||||
|
||||
if (companyForm.logo) {
|
||||
previewLogo.value.push({
|
||||
@ -218,6 +219,7 @@ function onFileInputChange(fileName, file, fileCount, fileList) {
|
||||
|
||||
function onFileInputRemove() {
|
||||
logoFileBlob.value = null
|
||||
isCompanyLogoRemoved.value = true
|
||||
}
|
||||
|
||||
async function updateCompanyData() {
|
||||
@ -232,18 +234,23 @@ async function updateCompanyData() {
|
||||
const res = await companyStore.updateCompany(companyForm)
|
||||
|
||||
if (res.data.data) {
|
||||
if (logoFileBlob.value) {
|
||||
if (logoFileBlob.value || isCompanyLogoRemoved.value) {
|
||||
let logoData = new FormData()
|
||||
|
||||
logoData.append(
|
||||
'company_logo',
|
||||
JSON.stringify({
|
||||
name: logoFileName.value,
|
||||
data: logoFileBlob.value,
|
||||
})
|
||||
)
|
||||
if (logoFileBlob.value) {
|
||||
logoData.append(
|
||||
'company_logo',
|
||||
JSON.stringify({
|
||||
name: logoFileName.value,
|
||||
data: logoFileBlob.value,
|
||||
})
|
||||
)
|
||||
}
|
||||
logoData.append('is_company_logo_removed', isCompanyLogoRemoved.value)
|
||||
|
||||
await companyStore.updateCompanyLogo(logoData)
|
||||
logoFileBlob.value = null
|
||||
isCompanyLogoRemoved.value = false
|
||||
}
|
||||
|
||||
isSaving.value = false
|
||||
|
||||
Reference in New Issue
Block a user