From e7301eb7a3660fb6f4adb2ea9a82ff99ea0bd65f Mon Sep 17 00:00:00 2001 From: harshjagad20 Date: Mon, 14 Mar 2022 11:54:13 +0530 Subject: [PATCH 1/5] Fix minor issues --- app/Http/Requests/CompaniesRequest.php | 7 ++-- app/Models/Company.php | 2 +- tests/Feature/Admin/EstimateTest.php | 49 +++++++++++----------- tests/Feature/Admin/ExpenseTest.php | 32 ++++++++------- tests/Feature/Admin/InvoiceTest.php | 56 ++++++++++++++------------ 5 files changed, 77 insertions(+), 69 deletions(-) diff --git a/app/Http/Requests/CompaniesRequest.php b/app/Http/Requests/CompaniesRequest.php index 5394592b..e9aa51d5 100644 --- a/app/Http/Requests/CompaniesRequest.php +++ b/app/Http/Requests/CompaniesRequest.php @@ -3,7 +3,6 @@ namespace Crater\Http\Requests; use Illuminate\Foundation\Http\FormRequest; -use Illuminate\Support\Str; use Illuminate\Validation\Rule; class CompaniesRequest extends FormRequest @@ -34,6 +33,9 @@ class CompaniesRequest extends FormRequest 'currency' => [ 'required' ], + 'currency' => [ + 'required' + ], 'address.name' => [ 'nullable', ], @@ -71,8 +73,7 @@ class CompaniesRequest extends FormRequest 'name' ]) ->merge([ - 'owner_id' => $this->user()->id, - 'slug' => Str::slug($this->name) + 'owner_id' => $this->user()->id ]) ->toArray(); } diff --git a/app/Models/Company.php b/app/Models/Company.php index bf87820b..a0d9fddb 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -217,7 +217,7 @@ class Company extends Model implements HasMedia 'estimate_billing_address_format' => $billingAddressFormat, 'payment_company_address_format' => $companyAddressFormat, 'payment_from_customer_address_format' => $paymentFromCustomerAddress, - 'currency' => request()->currency ?? 13, + 'currency' => request()->currency ?? 1, 'time_zone' => 'Asia/Kolkata', 'language' => 'en', 'fiscal_year' => '1-12', diff --git a/tests/Feature/Admin/EstimateTest.php b/tests/Feature/Admin/EstimateTest.php index c726c043..0a06f83d 100644 --- a/tests/Feature/Admin/EstimateTest.php +++ b/tests/Feature/Admin/EstimateTest.php @@ -415,32 +415,31 @@ test('update estimate with EUR currency', function () { $response = putJson('api/v1/estimates/'.$estimate->id, $estimate2); - $this->assertDatabaseHas('estimates', [ - 'id' => $estimate['id'], - 'template_name' => $estimate2['template_name'], - 'estimate_number' => $estimate2['estimate_number'], - 'discount_type' => $estimate2['discount_type'], - 'discount_val' => $estimate2['discount_val'], - 'sub_total' => $estimate2['sub_total'], - 'discount' => $estimate2['discount'], - 'customer_id' => $estimate2['customer_id'], - 'total' => $estimate2['total'], - 'tax' => $estimate2['tax'], - 'exchange_rate' => $estimate2['exchange_rate'], - 'base_discount_val' => $estimate2['base_discount_val'], - 'base_sub_total' => $estimate2['base_sub_total'], - 'base_total' => $estimate2['base_total'], - 'base_tax' => $estimate2['base_tax'], - ]); + $estimate_assert = collect($estimate2) + ->only([ + 'id', + 'template_name', + 'estimate_number', + 'discount_type', + 'discount_val', + 'sub_total', + 'discount', + 'customer_id', + 'total', + 'tax' + ]) + ->toArray(); - $this->assertDatabaseHas('estimate_items', [ - 'estimate_id' => $estimate2['items'][0]['estimate_id'], - 'exchange_rate' => $estimate2['items'][0]['exchange_rate'], - 'base_price' => $estimate2['items'][0]['base_price'], - 'base_discount_val' => $estimate2['items'][0]['base_discount_val'], - 'base_tax' => $estimate2['items'][0]['base_tax'], - 'base_total' => $estimate2['items'][0]['base_total'], - ]); + $this->assertDatabaseHas('estimates', $estimate_assert); + + $estimate_item_assert = collect($estimate2['items'][0]) + ->only([ + 'estimate_id', + 'amount' + ]) + ->toArray(); + + $this->assertDatabaseHas('estimate_items', $estimate_item_assert); $response->assertStatus(200); }); diff --git a/tests/Feature/Admin/ExpenseTest.php b/tests/Feature/Admin/ExpenseTest.php index 0e46c0f4..38a5c8dd 100644 --- a/tests/Feature/Admin/ExpenseTest.php +++ b/tests/Feature/Admin/ExpenseTest.php @@ -37,13 +37,15 @@ test('create expense', function () { postJson('api/v1/expenses', $expense)->assertStatus(201); - $this->assertDatabaseHas('expenses', [ - 'notes' => $expense['notes'], - 'expense_category_id' => $expense['expense_category_id'], - 'amount' => $expense['amount'], - 'exchange_rate' => $expense['exchange_rate'], - 'base_amount' => $expense['base_amount'], - ]); + $expense = collect($expense) + ->only([ + 'notes', + 'expense_category_id', + 'amount' + ]) + ->toArray(); + + $this->assertDatabaseHas('expenses', $expense); }); test('store validates using a form request', function () { @@ -146,11 +148,13 @@ test('update expense with EUR currency', function () { putJson('api/v1/expenses/'.$expense->id, $expense2)->assertOk(); - $this->assertDatabaseHas('expenses', [ - 'id' => $expense->id, - 'expense_category_id' => $expense2['expense_category_id'], - 'amount' => $expense2['amount'], - 'exchange_rate' => $expense2['exchange_rate'], - 'base_amount' => $expense2['base_amount'], - ]); + $expense2 = collect($expense2) + ->only([ + 'id', + 'expense_category_id', + 'amount' + ]) + ->toArray(); + + $this->assertDatabaseHas('expenses', $expense2); }); diff --git a/tests/Feature/Admin/InvoiceTest.php b/tests/Feature/Admin/InvoiceTest.php index ef8a716e..dce605a5 100644 --- a/tests/Feature/Admin/InvoiceTest.php +++ b/tests/Feature/Admin/InvoiceTest.php @@ -9,7 +9,6 @@ use Crater\Models\Tax; use Crater\Models\User; use Illuminate\Support\Facades\Artisan; use Laravel\Sanctum\Sanctum; - use function Pest\Laravel\getJson; use function Pest\Laravel\postJson; use function Pest\Laravel\putJson; @@ -431,31 +430,36 @@ test('update invoice with EUR currency', function () { putJson('api/v1/invoices/'.$invoice->id, $invoice2)->assertOk(); - $this->assertDatabaseHas('invoices', [ - 'id' => $invoice['id'], - 'invoice_number' => $invoice2['invoice_number'], - 'sub_total' => $invoice2['sub_total'], - 'total' => $invoice2['total'], - 'tax' => $invoice2['tax'], - 'discount' => $invoice2['discount'], - 'customer_id' => $invoice2['customer_id'], - 'template_name' => $invoice2['template_name'], - 'exchange_rate' => $invoice2['exchange_rate'], - 'base_total' => $invoice2['base_total'], - ]); + $invoice_assert = collect($invoice2) + ->only([ + 'invoice_number', + 'template_name', + 'sub_total', + 'total', + 'tax', + 'discount', + 'customer_id', + ]) + ->toArray(); - $this->assertDatabaseHas('invoice_items', [ - 'invoice_id' => $invoice2['items'][0]['invoice_id'], - 'item_id' => $invoice2['items'][0]['item_id'], - 'name' => $invoice2['items'][0]['name'], - 'exchange_rate' => $invoice2['items'][0]['exchange_rate'], - 'base_price' => $invoice2['items'][0]['base_price'], - 'base_total' => $invoice2['items'][0]['base_total'], - ]); + $this->assertDatabaseHas('invoices', $invoice_assert); - $this->assertDatabaseHas('taxes', [ - 'amount' => $invoice2['taxes'][0]['amount'], - 'name' => $invoice2['taxes'][0]['name'], - 'base_amount' => $invoice2['taxes'][0]['base_amount'], - ]); + $invoice_item_assert = collect($invoice2['items'][0]) + ->only([ + 'invoice_id', + 'item_id', + 'name', + ]) + ->toArray(); + + $this->assertDatabaseHas('invoice_items', $invoice_item_assert); + + $invoice_tax_assert = collect($invoice2['taxes'][0]) + ->only([ + 'name', + 'amount' + ]) + ->toArray(); + + $this->assertDatabaseHas('taxes', $invoice_tax_assert); }); From 0e31f85c181572d3e6c9dc253233722463085ee6 Mon Sep 17 00:00:00 2001 From: asift798 Date: Mon, 14 Mar 2022 12:55:38 +0530 Subject: [PATCH 2/5] change company currency if it does not have any transaction. --- resources/scripts/admin/stores/company.js | 14 ++++++++++++++ .../admin/views/settings/PreferencesSetting.vue | 13 +++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/resources/scripts/admin/stores/company.js b/resources/scripts/admin/stores/company.js index 1e10489b..f5462ae0 100644 --- a/resources/scripts/admin/stores/company.js +++ b/resources/scripts/admin/stores/company.js @@ -184,6 +184,20 @@ export const useCompanyStore = (useWindow = false) => { setDefaultCurrency(data) { this.defaultCurrency = data.currency }, + + checkCompanyHasCurrencyTransactions() { + return new Promise((resolve, reject) => { + axios + .get(`/api/v1/company/has-transactions`) + .then((response) => { + resolve(response) + }) + .catch((err) => { + handleError(err) + reject(err) + }) + }) + }, }, })() } diff --git a/resources/scripts/admin/views/settings/PreferencesSetting.vue b/resources/scripts/admin/views/settings/PreferencesSetting.vue index 6c46f645..531cb83d 100644 --- a/resources/scripts/admin/views/settings/PreferencesSetting.vue +++ b/resources/scripts/admin/views/settings/PreferencesSetting.vue @@ -8,7 +8,11 @@ @@ -21,7 +25,7 @@ :searchable="true" track-by="name" :invalid="v$.currency.$error" - disabled + :disabled="isCurrencyDisabled" class="w-full" > @@ -187,6 +191,7 @@ const { t, tm } = useI18n() let isSaving = ref(false) let isDataSaving = ref(false) let isFetchingInitialData = ref(false) +let isCurrencyDisabled = ref(true) const settingsForm = reactive({ ...companyStore.selectedCompanySettings }) @@ -282,10 +287,14 @@ setInitialData() async function setInitialData() { isFetchingInitialData.value = true Promise.all([ + companyStore.checkCompanyHasCurrencyTransactions(), globalStore.fetchCurrencies(), globalStore.fetchDateFormats(), globalStore.fetchTimeZones(), ]).then(([res1]) => { + if (res1.data?.has_transactions == false) { + isCurrencyDisabled.value = false + } isFetchingInitialData.value = false }) } From 20c2502e3172cd4f93c0db62b3f054d5b9fb8c55 Mon Sep 17 00:00:00 2001 From: asift798 Date: Mon, 14 Mar 2022 17:45:58 +0530 Subject: [PATCH 3/5] added company slug --- app/Http/Requests/CompaniesRequest.php | 5 +- .../modal-components/CompanyModal.vue | 55 +++++++++++++++- .../views/installation/Step7CompanyInfo.vue | 62 +++++++++++++++++-- .../views/settings/CompanyInfoSettings.vue | 22 ++++++- resources/scripts/locales/en.json | 7 ++- 5 files changed, 141 insertions(+), 10 deletions(-) diff --git a/app/Http/Requests/CompaniesRequest.php b/app/Http/Requests/CompaniesRequest.php index e9aa51d5..53002d47 100644 --- a/app/Http/Requests/CompaniesRequest.php +++ b/app/Http/Requests/CompaniesRequest.php @@ -33,7 +33,7 @@ class CompaniesRequest extends FormRequest 'currency' => [ 'required' ], - 'currency' => [ + 'slug' => [ 'required' ], 'address.name' => [ @@ -70,7 +70,8 @@ class CompaniesRequest extends FormRequest { return collect($this->validated()) ->only([ - 'name' + 'name', + 'slug' ]) ->merge([ 'owner_id' => $this->user()->id diff --git a/resources/scripts/admin/components/modal-components/CompanyModal.vue b/resources/scripts/admin/components/modal-components/CompanyModal.vue index 019a065c..61cdce02 100644 --- a/resources/scripts/admin/components/modal-components/CompanyModal.vue +++ b/resources/scripts/admin/components/modal-components/CompanyModal.vue @@ -48,6 +48,23 @@ /> + + + + import { useModalStore } from '@/scripts/stores/modal' -import { computed, onMounted, ref, reactive } from 'vue' +import { computed, onMounted, ref, reactive, watch } from 'vue' import { useI18n } from 'vue-i18n' import { required, minLength, helpers } from '@vuelidate/validators' import { useVuelidate } from '@vuelidate/core' @@ -152,6 +169,7 @@ let companyLogoName = ref(null) const newCompanyForm = reactive({ name: null, + slug: null, currency: '', address: { country_id: null, @@ -162,6 +180,9 @@ const modalActive = computed(() => { return modalStore.active && modalStore.componentName === 'CompanyModal' }) +const slugValidator = (value) => { + return value == slugify(value) +} const rules = { newCompanyForm: { name: { @@ -171,6 +192,17 @@ const rules = { minLength(3) ), }, + slug: { + required: helpers.withMessage(t('validation.required'), required), + minLength: helpers.withMessage( + t('validation.name_min_length', { count: 3 }), + minLength(3) + ), + slugValidator: helpers.withMessage( + t('validation.invalid_slug'), + slugValidator + ), + }, address: { country_id: { required: helpers.withMessage(t('validation.required'), required), @@ -243,6 +275,7 @@ async function submitCompanyData() { function resetNewCompanyForm() { newCompanyForm.name = '' + newCompanyForm.slug = '' newCompanyForm.currency = '' newCompanyForm.address.country_id = '' @@ -257,4 +290,24 @@ function closeCompanyModal() { v$.value.$reset() }, 300) } + +// watcher for if change company name then auto fill company slug value +watch( + () => newCompanyForm.name, + (currentValue) => { + newCompanyForm.slug = slugify(currentValue) + } +) + +function slugify(string) { + return string + .toString() + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/[^\w\-]+/g, '') + .replace(/\-\-+/g, '-') + .replace(/^-+/, '') + .replace(/-+$/, '') +} diff --git a/resources/scripts/admin/views/installation/Step7CompanyInfo.vue b/resources/scripts/admin/views/installation/Step7CompanyInfo.vue index 3890ccbd..12a0a6df 100644 --- a/resources/scripts/admin/views/installation/Step7CompanyInfo.vue +++ b/resources/scripts/admin/views/installation/Step7CompanyInfo.vue @@ -34,6 +34,23 @@ /> + + + + - -
diff --git a/resources/scripts/admin/views/settings/CompanyInfoSettings.vue b/resources/scripts/admin/views/settings/CompanyInfoSettings.vue index 357b7dd6..d3723910 100644 --- a/resources/scripts/admin/views/settings/CompanyInfoSettings.vue +++ b/resources/scripts/admin/views/settings/CompanyInfoSettings.vue @@ -28,6 +28,18 @@ /> + + + + @@ -160,6 +172,7 @@ let isSaving = ref(false) const companyForm = reactive({ name: null, + slug: null, logo: null, address: { address_street_1: '', @@ -193,7 +206,14 @@ const rules = computed(() => { name: { required: helpers.withMessage(t('validation.required'), required), minLength: helpers.withMessage( - t('validation.name_min_length'), + t('validation.name_min_length', { count: 3 }), + minLength(3) + ), + }, + slug: { + required: helpers.withMessage(t('validation.required'), required), + minLength: helpers.withMessage( + t('validation.name_min_length', { count: 3 }), minLength(3) ), }, diff --git a/resources/scripts/locales/en.json b/resources/scripts/locales/en.json index 5c224428..7f273fa9 100644 --- a/resources/scripts/locales/en.json +++ b/resources/scripts/locales/en.json @@ -863,6 +863,7 @@ "company_info": { "company_info": "Company info", "company_name": "Company Name", + "company_slug": "Company Slug", "company_logo": "Company Logo", "section_description": "Information about your company that will be displayed on invoices, estimates and other documents created by Crater.", "phone": "Phone", @@ -1324,6 +1325,7 @@ "company_info": "Company Information", "company_info_desc": "This information will be displayed on invoices. Note that you can edit this later on settings page.", "company_name": "Company Name", + "company_slug": "Company Slug", "company_logo": "Company Logo", "logo_preview": "Logo Preview", "preferences": "Company Preferences", @@ -1454,7 +1456,8 @@ "at_least_one_ability": "Please select atleast one Permission.", "valid_driver_key": "Please enter a valid {driver} key.", "valid_exchange_rate": "Please enter a valid exchange rate.", - "company_name_not_same": "Company name must match with given name." + "company_name_not_same": "Company name must match with given name.", + "invalid_slug": "Invalid Slug" }, "errors": { "starter_plan": "This feature is available on Starter plan and onwards!", @@ -1523,4 +1526,4 @@ "pdf_ship_to": "Ship to,", "pdf_received_from": "Received from:", "pdf_tax_label": "Tax" -} +} \ No newline at end of file From 5c63770b6bb0968cfb7bcc94811e0bbf608e93d7 Mon Sep 17 00:00:00 2001 From: asift798 Date: Mon, 21 Mar 2022 12:04:17 +0530 Subject: [PATCH 4/5] added unique validation and help text for company slug field --- app/Http/Requests/CompaniesRequest.php | 3 ++- app/Http/Requests/CompanyRequest.php | 3 ++- .../scripts/admin/components/modal-components/CompanyModal.vue | 1 + .../scripts/admin/views/installation/Step7CompanyInfo.vue | 1 + resources/scripts/admin/views/settings/CompanyInfoSettings.vue | 1 + resources/scripts/locales/en.json | 2 ++ 6 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/Http/Requests/CompaniesRequest.php b/app/Http/Requests/CompaniesRequest.php index 53002d47..661d8777 100644 --- a/app/Http/Requests/CompaniesRequest.php +++ b/app/Http/Requests/CompaniesRequest.php @@ -34,7 +34,8 @@ class CompaniesRequest extends FormRequest 'required' ], 'slug' => [ - 'required' + 'required', + Rule::unique('companies') ], 'address.name' => [ 'nullable', diff --git a/app/Http/Requests/CompanyRequest.php b/app/Http/Requests/CompanyRequest.php index c86cd645..dc22b1ae 100644 --- a/app/Http/Requests/CompanyRequest.php +++ b/app/Http/Requests/CompanyRequest.php @@ -30,7 +30,8 @@ class CompanyRequest extends FormRequest Rule::unique('companies')->ignore($this->header('company'), 'id'), ], 'slug' => [ - 'nullable' + 'required', + Rule::unique('companies')->ignore($this->header('company'), 'id'), ], 'address.country_id' => [ 'required', diff --git a/resources/scripts/admin/components/modal-components/CompanyModal.vue b/resources/scripts/admin/components/modal-components/CompanyModal.vue index 61cdce02..011218a1 100644 --- a/resources/scripts/admin/components/modal-components/CompanyModal.vue +++ b/resources/scripts/admin/components/modal-components/CompanyModal.vue @@ -50,6 +50,7 @@ diff --git a/resources/scripts/locales/en.json b/resources/scripts/locales/en.json index 7f273fa9..0cc68a90 100644 --- a/resources/scripts/locales/en.json +++ b/resources/scripts/locales/en.json @@ -864,6 +864,7 @@ "company_info": "Company info", "company_name": "Company Name", "company_slug": "Company Slug", + "company_slug_help_text": "A unique URL friendly name for your company. It will be used for the URL of your Customer Portal.", "company_logo": "Company Logo", "section_description": "Information about your company that will be displayed on invoices, estimates and other documents created by Crater.", "phone": "Phone", @@ -1326,6 +1327,7 @@ "company_info_desc": "This information will be displayed on invoices. Note that you can edit this later on settings page.", "company_name": "Company Name", "company_slug": "Company Slug", + "company_slug_help_text": "A unique URL friendly name for your company. It will be used for the URL of your Customer Portal.", "company_logo": "Company Logo", "logo_preview": "Logo Preview", "preferences": "Company Preferences", From ef35293f8abeb1347218fcdd8a167063329ce3ce Mon Sep 17 00:00:00 2001 From: asift798 Date: Mon, 21 Mar 2022 12:13:05 +0530 Subject: [PATCH 5/5] update company slug help text --- resources/scripts/locales/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/scripts/locales/en.json b/resources/scripts/locales/en.json index 0cc68a90..a462b9fb 100644 --- a/resources/scripts/locales/en.json +++ b/resources/scripts/locales/en.json @@ -864,7 +864,7 @@ "company_info": "Company info", "company_name": "Company Name", "company_slug": "Company Slug", - "company_slug_help_text": "A unique URL friendly name for your company. It will be used for the URL of your Customer Portal.", + "company_slug_help_text": "A unique URL friendly name for your company (It will appear on Customer Portal URL)", "company_logo": "Company Logo", "section_description": "Information about your company that will be displayed on invoices, estimates and other documents created by Crater.", "phone": "Phone", @@ -1327,7 +1327,7 @@ "company_info_desc": "This information will be displayed on invoices. Note that you can edit this later on settings page.", "company_name": "Company Name", "company_slug": "Company Slug", - "company_slug_help_text": "A unique URL friendly name for your company. It will be used for the URL of your Customer Portal.", + "company_slug_help_text": "A unique URL friendly name for your company (It will appear on Customer Portal URL)", "company_logo": "Company Logo", "logo_preview": "Logo Preview", "preferences": "Company Preferences",