Compare commits

...

5 Commits

Author SHA1 Message Date
Ahmed Bouhuolia
88ff5db0f3 Merge pull request #989 from bigcapitalhq/fix/organization-date-formats-and-address-fields
fix(organization): align date formats and fix address field naming
2026-02-24 22:45:10 +02:00
Ahmed Bouhuolia
f35e85c3d2 fix(organization): align date formats and fix address field naming
- Fix date format mismatch between Miscellaneous and Organization constants
- Fix default date format casing ('DD MMM yyyy' -> 'DD MMM YYYY')
- Rename address fields from address_1/address_2 to address1/address2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-24 22:42:29 +02:00
Ahmed Bouhuolia
29decf9c5a Merge pull request #987 from bigcapitalhq/feat/contact-address-country-fields
fix: country and address fields of customer and vendor forms
2026-02-24 20:55:23 +02:00
Ahmed Bouhuolia
f149ff43b4 feat(contacts): add country field to customer and vendor address forms
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-24 20:53:14 +02:00
Ahmed Bouhuolia
fb05af8c00 Merge pull request #979 from yk-a11y/fix/credit-note-apply-invoice-validation
fix: validate credit note per-entry amount against each invoice due amount
2026-02-24 02:55:47 +02:00
15 changed files with 73 additions and 53 deletions

View File

@@ -10,7 +10,7 @@ export interface IContactAddress {
billingAddressCity: string; billingAddressCity: string;
billingAddressCountry: string; billingAddressCountry: string;
billingAddressEmail: string; billingAddressEmail: string;
billingAddressZipcode: string; billingAddressPostcode: string;
billingAddressPhone: string; billingAddressPhone: string;
billingAddressState: string; billingAddressState: string;
@@ -19,7 +19,7 @@ export interface IContactAddress {
shippingAddressCity: string; shippingAddressCity: string;
shippingAddressCountry: string; shippingAddressCountry: string;
shippingAddressEmail: string; shippingAddressEmail: string;
shippingAddressZipcode: string; shippingAddressPostcode: string;
shippingAddressPhone: string; shippingAddressPhone: string;
shippingAddressState: string; shippingAddressState: string;
} }
@@ -29,7 +29,7 @@ export interface IContactAddressDTO {
billingAddressCity?: string; billingAddressCity?: string;
billingAddressCountry?: string; billingAddressCountry?: string;
billingAddressEmail?: string; billingAddressEmail?: string;
billingAddressZipcode?: string; billingAddressPostcode?: string;
billingAddressPhone?: string; billingAddressPhone?: string;
billingAddressState?: string; billingAddressState?: string;
@@ -38,7 +38,7 @@ export interface IContactAddressDTO {
shippingAddressCity?: string; shippingAddressCity?: string;
shippingAddressCountry?: string; shippingAddressCountry?: string;
shippingAddressEmail?: string; shippingAddressEmail?: string;
shippingAddressZipcode?: string; shippingAddressPostcode?: string;
shippingAddressPhone?: string; shippingAddressPhone?: string;
shippingAddressState?: string; shippingAddressState?: string;
} }

View File

@@ -27,10 +27,10 @@ export class ContactAddressDto {
@IsEmail() @IsEmail()
billingAddressEmail?: string; billingAddressEmail?: string;
@ApiProperty({ required: false, description: 'Billing address zipcode' }) @ApiProperty({ required: false, description: 'Billing address postcode' })
@IsOptional() @IsOptional()
@IsString() @IsString()
billingAddressZipcode?: string; billingAddressPostcode?: string;
@ApiProperty({ required: false, description: 'Billing address phone' }) @ApiProperty({ required: false, description: 'Billing address phone' })
@IsOptional() @IsOptional()
@@ -67,10 +67,10 @@ export class ContactAddressDto {
@IsEmail() @IsEmail()
shippingAddressEmail?: string; shippingAddressEmail?: string;
@ApiProperty({ required: false, description: 'Shipping address zipcode' }) @ApiProperty({ required: false, description: 'Shipping address postcode' })
@IsOptional() @IsOptional()
@IsString() @IsString()
shippingAddressZipcode?: string; shippingAddressPostcode?: string;
@ApiProperty({ required: false, description: 'Shipping address phone' }) @ApiProperty({ required: false, description: 'Shipping address phone' })
@IsOptional() @IsOptional()

View File

@@ -1,18 +1,15 @@
import currencies from 'js-money/lib/currency'; import currencies from 'js-money/lib/currency';
export const DATE_FORMATS = [ export const DATE_FORMATS = [
'MM.dd.yy', 'MM/DD/YY',
'dd.MM.yy', 'DD/MM/YY',
'yy.MM.dd', 'YY/MM/DD',
'MM.dd.yyyy', 'MM/DD/yyyy',
'dd.MM.yyyy', 'DD/MM/yyyy',
'yyyy.MM.dd', 'yyyy/MM/DD',
'MM/DD/YYYY', 'DD MMM YYYY',
'M/D/YYYY', 'DD MMMM YYYY',
'dd MMM YYYY', 'MMMM DD, YYYY',
'dd MMMM YYYY',
'MMMM dd, YYYY',
'EEE, MMMM dd, YYYY',
]; ];
export const MONTHS = [ export const MONTHS = [
'january', 'january',

View File

@@ -12,6 +12,6 @@ export const transformBuildDto = (
): BuildOrganizationDto => { ): BuildOrganizationDto => {
return { return {
...buildDTO, ...buildDTO,
dateFormat: defaultTo(buildDTO.dateFormat, 'DD MMM yyyy'), dateFormat: defaultTo(buildDTO.dateFormat, 'DD MMM YYYY'),
}; };
}; };

View File

@@ -48,7 +48,10 @@ export class EditVendorDto extends ContactAddressDto {
@IsString() @IsString()
personalPhone?: string; personalPhone?: string;
@ApiProperty({ required: false, description: 'Additional notes about the vendor' }) @ApiProperty({
required: false,
description: 'Additional notes about the vendor',
})
@IsOptional() @IsOptional()
@IsString() @IsString()
note?: string; note?: string;

View File

@@ -27,20 +27,20 @@ const CustomerBillingAddress = ({}) => {
{/*------------ Billing Address 1 -----------*/} {/*------------ Billing Address 1 -----------*/}
<FFormGroup <FFormGroup
name={'billing_address_1'} name={'billing_address1'}
label={<T id={'address_line_1'} />} label={<T id={'address_line_1'} />}
inline={true} inline={true}
> >
<FTextArea name={'billing_address_1'} /> <FTextArea name={'billing_address1'} />
</FFormGroup> </FFormGroup>
{/*------------ Billing Address 2 -----------*/} {/*------------ Billing Address 2 -----------*/}
<FFormGroup <FFormGroup
name={'billing_address_2'} name={'billing_address2'}
label={<T id={'address_line_2'} />} label={<T id={'address_line_2'} />}
inline={true} inline={true}
> >
<FTextArea name={'billing_address_2'} /> <FTextArea name={'billing_address2'} />
</FFormGroup> </FFormGroup>
{/*------------ Billing Address city -----------*/} {/*------------ Billing Address city -----------*/}
<FFormGroup <FFormGroup
@@ -93,20 +93,20 @@ const CustomerBillingAddress = ({}) => {
{/*------------ Shipping Address 1 -----------*/} {/*------------ Shipping Address 1 -----------*/}
<FFormGroup <FFormGroup
name={'shipping_address_1'} name={'shipping_address1'}
label={<T id={'address_line_1'} />} label={<T id={'address_line_1'} />}
inline={true} inline={true}
> >
<FTextArea name={'shipping_address_1'} /> <FTextArea name={'shipping_address1'} />
</FFormGroup> </FFormGroup>
{/*------------ Shipping Address 2 -----------*/} {/*------------ Shipping Address 2 -----------*/}
<FFormGroup <FFormGroup
name={'shipping_address_2'} name={'shipping_address2'}
label={<T id={'address_line_2'} />} label={<T id={'address_line_2'} />}
inline={true} inline={true}
> >
<FTextArea name={'shipping_address_2'} /> <FTextArea name={'shipping_address2'} />
</FFormGroup> </FFormGroup>
{/*------------ Shipping Address city -----------*/} {/*------------ Shipping Address city -----------*/}

View File

@@ -25,16 +25,16 @@ const Schema = Yup.object().shape({
note: Yup.string().trim(), note: Yup.string().trim(),
billing_address_country: Yup.string().trim(), billing_address_country: Yup.string().trim(),
billing_address_1: Yup.string().trim(), billing_address1: Yup.string().trim(),
billing_address_2: Yup.string().trim(), billing_address2: Yup.string().trim(),
billing_address_city: Yup.string().trim(), billing_address_city: Yup.string().trim(),
billing_address_state: Yup.string().trim(), billing_address_state: Yup.string().trim(),
billing_address_postcode: Yup.string().nullable(), billing_address_postcode: Yup.string().nullable(),
billing_address_phone: Yup.string().nullable(), billing_address_phone: Yup.string().nullable(),
shipping_address_country: Yup.string().trim(), shipping_address_country: Yup.string().trim(),
shipping_address_1: Yup.string().trim(), shipping_address1: Yup.string().trim(),
shipping_address_2: Yup.string().trim(), shipping_address2: Yup.string().trim(),
shipping_address_city: Yup.string().trim(), shipping_address_city: Yup.string().trim(),
shipping_address_state: Yup.string().trim(), shipping_address_state: Yup.string().trim(),
shipping_address_postcode: Yup.string().nullable(), shipping_address_postcode: Yup.string().nullable(),

View File

@@ -8,7 +8,7 @@ import styled from 'styled-components';
import { CLASSES } from '@/constants/classes'; import { CLASSES } from '@/constants/classes';
import { CreateCustomerForm, EditCustomerForm } from './CustomerForm.schema'; import { CreateCustomerForm, EditCustomerForm } from './CustomerForm.schema';
import { compose, transformToForm, saveInvoke } from '@/utils'; import { compose, transformToForm, saveInvoke, parseBoolean } from '@/utils';
import { useCustomerFormContext } from './CustomerFormProvider'; import { useCustomerFormContext } from './CustomerFormProvider';
import { defaultInitialValues } from './utils'; import { defaultInitialValues } from './utils';
@@ -60,7 +60,10 @@ function CustomerFormFormik({
// Handles the form submit. // Handles the form submit.
const handleFormSubmit = (values, formArgs) => { const handleFormSubmit = (values, formArgs) => {
const { setSubmitting, resetForm } = formArgs; const { setSubmitting, resetForm } = formArgs;
const formValues = { ...values }; const formValues = {
...values,
active: parseBoolean(values.active, true),
};
const onSuccess = (res) => { const onSuccess = (res) => {
AppToaster.show({ AppToaster.show({

View File

@@ -55,7 +55,7 @@ export default function CustomerFormPrimarySection({}) {
label={<T id={'company_name'} />} label={<T id={'company_name'} />}
inline={true} inline={true}
> >
<InputGroup name={'company_name'} /> <FInputGroup name={'company_name'} />
</FFormGroup> </FFormGroup>
{/*----------- Display Name -----------*/} {/*----------- Display Name -----------*/}

View File

@@ -23,16 +23,16 @@ export const defaultInitialValues = {
active: true, active: true,
billing_address_country: '', billing_address_country: '',
billing_address_1: '', billing_address1: '',
billing_address_2: '', billing_address2: '',
billing_address_city: '', billing_address_city: '',
billing_address_state: '', billing_address_state: '',
billing_address_postcode: '', billing_address_postcode: '',
billing_address_phone: '', billing_address_phone: '',
shipping_address_country: '', shipping_address_country: '',
shipping_address_1: '', shipping_address1: '',
shipping_address_2: '', shipping_address2: '',
shipping_address_city: '', shipping_address_city: '',
shipping_address_state: '', shipping_address_state: '',
shipping_address_postcode: '', shipping_address_postcode: '',

View File

@@ -111,12 +111,12 @@ export default function PreferencesGeneralForm({ isSubmitting }) {
> >
<Stack> <Stack>
<FInputGroup <FInputGroup
name={'address.address_1'} name={'address.address1'}
placeholder={'Address 1'} placeholder={'Address 1'}
fastField fastField
/> />
<FInputGroup <FInputGroup
name={'address.address_2'} name={'address.address2'}
placeholder={'Address 2'} placeholder={'Address 2'}
fastField fastField
/> />

View File

@@ -18,16 +18,16 @@ const Schema = Yup.object().shape({
note: Yup.string().trim(), note: Yup.string().trim(),
billing_address_country: Yup.string().trim(), billing_address_country: Yup.string().trim(),
billing_address_1: Yup.string().trim(), billing_address1: Yup.string().trim(),
billing_address_2: Yup.string().trim(), billing_address2: Yup.string().trim(),
billing_address_city: Yup.string().trim(), billing_address_city: Yup.string().trim(),
billing_address_state: Yup.string().trim(), billing_address_state: Yup.string().trim(),
billing_address_postcode: Yup.string().nullable(), billing_address_postcode: Yup.string().nullable(),
billing_address_phone: Yup.string().nullable(), billing_address_phone: Yup.string().nullable(),
shipping_address_country: Yup.string().trim(), shipping_address_country: Yup.string().trim(),
shipping_address_1: Yup.string().trim(), shipping_address1: Yup.string().trim(),
shipping_address_2: Yup.string().trim(), shipping_address2: Yup.string().trim(),
shipping_address_city: Yup.string().trim(), shipping_address_city: Yup.string().trim(),
shipping_address_state: Yup.string().trim(), shipping_address_state: Yup.string().trim(),
shipping_address_postcode: Yup.string().nullable(), shipping_address_postcode: Yup.string().nullable(),

View File

@@ -21,7 +21,7 @@ import VendorFloatingActions from './VendorFloatingActions';
import { withCurrentOrganization } from '@/containers/Organization/withCurrentOrganization'; import { withCurrentOrganization } from '@/containers/Organization/withCurrentOrganization';
import { useVendorFormContext } from './VendorFormProvider'; import { useVendorFormContext } from './VendorFormProvider';
import { compose, transformToForm, safeInvoke } from '@/utils'; import { compose, transformToForm, safeInvoke, parseBoolean } from '@/utils';
import { defaultInitialValues } from './utils'; import { defaultInitialValues } from './utils';
import '@/style/pages/Vendors/Form.scss'; import '@/style/pages/Vendors/Form.scss';
@@ -69,7 +69,10 @@ function VendorFormFormik({
// Handles the form submit. // Handles the form submit.
const handleFormSubmit = (values, form) => { const handleFormSubmit = (values, form) => {
const { setSubmitting, resetForm } = form; const { setSubmitting, resetForm } = form;
const requestForm = { ...values }; const requestForm = {
...values,
active: parseBoolean(values.active, true),
};
setSubmitting(true); setSubmitting(true);

View File

@@ -22,16 +22,16 @@ export const defaultInitialValues = {
active: true, active: true,
billing_address_country: '', billing_address_country: '',
billing_address_1: '', billing_address1: '',
billing_address_2: '', billing_address2: '',
billing_address_city: '', billing_address_city: '',
billing_address_state: '', billing_address_state: '',
billing_address_postcode: '', billing_address_postcode: '',
billing_address_phone: '', billing_address_phone: '',
shipping_address_country: '', shipping_address_country: '',
shipping_address_1: '', shipping_address1: '',
shipping_address_2: '', shipping_address2: '',
shipping_address_city: '', shipping_address_city: '',
shipping_address_state: '', shipping_address_state: '',
shipping_address_postcode: '', shipping_address_postcode: '',

View File

@@ -84,6 +84,20 @@ export const handleBooleanChange = (handler) => {
return (event) => handler(event.target.checked); return (event) => handler(event.target.checked);
}; };
/**
* Parses a value to boolean (handles 1, 0, '1', '0', true, false).
* @param {*} value
* @param {boolean} defaultValue - value when empty/unknown
* @returns {boolean}
*/
export const parseBoolean = (value, defaultValue = false) => {
if (typeof value === 'boolean') return value;
if (value === 1 || value === '1') return true;
if (value === 0 || value === '0') return false;
if (value == null || value === '') return defaultValue;
return Boolean(value);
};
/** Event handler that exposes the target element's value as a string. */ /** Event handler that exposes the target element's value as a string. */
export const handleStringChange = (handler) => { export const handleStringChange = (handler) => {
return (event) => handler(event.target.value); return (event) => handler(event.target.value);