feat: rename item sku to code.

feat: fix sidebar current tab issue.
This commit is contained in:
Ahmed Bouhuolia
2020-11-24 11:30:27 +02:00
parent a7e5401b7d
commit 0321f29442
20 changed files with 75 additions and 50 deletions

View File

@@ -3,5 +3,5 @@ import React from 'react';
export default function MenuItemLabel({ export default function MenuItemLabel({
text text
}) { }) {
return (<span class="bp3-menu-item-label">{ text }</span>); return (<span class="bp3-menu-item-labeler">{ text }</span>);
} }

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React, { useMemo } from 'react';
import { Menu, MenuDivider } from '@blueprintjs/core'; import { Menu, MenuDivider, Button } from '@blueprintjs/core';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import sidebarMenuList from 'config/sidebarMenu'; import sidebarMenuList from 'config/sidebarMenu';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
@@ -16,16 +16,31 @@ export default function SidebarMenu() {
const children = Array.isArray(item.children) const children = Array.isArray(item.children)
? menuItemsMapper(item.children) ? menuItemsMapper(item.children)
: null; : null;
const isActive =
(item.href && item.href === location.pathname) || const matchPath = (pathname, path) => {
(item.children && return item.matchExact ? pathname === path : pathname.indexOf(path) !== -1;
item.children.some((c) => c.href === location.pathname)); };
const isActive = (item.children) ?
item.children.some((c) => matchPath(location.pathname, c.href)) :
(item.href && matchPath(location.pathname, item.href));
const handleItemClick = () => { const handleItemClick = () => {
if (item.href) { if (item.href) {
history.push(item.href); history.push(item.href);
} }
}; };
const maybeRenderLabel = (item) => item.newTabHref ? (
<Button
className="menu-item__add-btn"
icon={<Icon icon={'plus'} iconSize={16} />}
onClick={(event) => {
history.push(item.newTabHref);
event.stopPropagation();
}}
/>
) : null;
return item.spacer ? ( return item.spacer ? (
<div class="bp3-menu-spacer"></div> <div class="bp3-menu-spacer"></div>
) : item.divider ? ( ) : item.divider ? (
@@ -38,7 +53,7 @@ export default function SidebarMenu() {
active={isActive} active={isActive}
icon={<Icon icon={item.icon} iconSize={item.iconSize} />} icon={<Icon icon={item.icon} iconSize={item.iconSize} />}
text={item.text} text={item.text}
label={item.label} label={maybeRenderLabel(item)}
disabled={item.disabled} disabled={item.disabled}
children={children} children={children}
dropdownType={item.dropdownType || 'collapse'} dropdownType={item.dropdownType || 'collapse'}

View File

@@ -1,4 +1,4 @@
import React from 'react'; import React from 'react';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
export default [ export default [
@@ -13,7 +13,6 @@ export default [
{ {
divider: true, divider: true,
}, },
{ {
text: 'Sales & inventory', text: 'Sales & inventory',
label: true, label: true,
@@ -41,16 +40,18 @@ export default [
{ {
text: <T id={'estimates'} />, text: <T id={'estimates'} />,
href: '/estimates', href: '/estimates',
newTabHref: '/estimates/new',
}, },
{ {
text: <T id={'invocies'} />, text: <T id={'invocies'} />,
href: '/invoices', href: '/invoices',
newTabHref: '/invoices/new',
}, },
{ {
text: <T id={'payment_receives'} />, text: <T id={'payment_receives'} />,
href: '/payment-receives', href: '/payment-receives',
newTabHref: '/payment-receives/new',
}, },
{ {
divider: true, divider: true,
@@ -58,6 +59,7 @@ export default [
{ {
text: <T id={'receipts'} />, text: <T id={'receipts'} />,
href: '/receipts', href: '/receipts',
newTabHref: '/receipts/new',
}, },
], ],
}, },
@@ -67,11 +69,12 @@ export default [
{ {
text: <T id={'bills'} />, text: <T id={'bills'} />,
href: '/bills', href: '/bills',
newTabHref: '/bills/new',
}, },
{ {
text: <T id={'payment_made'} />, text: <T id={'payment_made'} />,
href: '/payment-mades', href: '/payment-mades',
newTabHref: '/payment-mades/new',
}, },
], ],
}, },
@@ -81,10 +84,12 @@ export default [
{ {
text: <T id={'customers'} />, text: <T id={'customers'} />,
href: '/customers', href: '/customers',
newTabHref: '/customers/new',
}, },
{ {
text: <T id={'vendors'} />, text: <T id={'vendors'} />,
href: '/vendors', href: '/vendors',
newTabHref: '/vendors/new',
}, },
], ],
}, },
@@ -139,6 +144,7 @@ export default [
{ {
text: <T id={'all_reports'} />, text: <T id={'all_reports'} />,
href: '/financial-reports', href: '/financial-reports',
matchExact: true,
}, },
{ {
divider: true, divider: true,

View File

@@ -9,6 +9,9 @@ export default function EditableItemsEntriesTable({
defaultEntry, defaultEntry,
minLinesNumber = 2, minLinesNumber = 2,
linesNumber = 5, linesNumber = 5,
filterSellableItems = false,
filterPurchasableItems = false,
}) { }) {
const { setFieldValue, values } = useFormikContext(); const { setFieldValue, values } = useFormikContext();
const [clearLinesAlert, setClearLinesAlert] = useState(false); const [clearLinesAlert, setClearLinesAlert] = useState(false);
@@ -58,6 +61,8 @@ export default function EditableItemsEntriesTable({
}} }}
entries={value} entries={value}
errors={error} errors={error}
filterPurchasableItems={filterPurchasableItems}
filterSellableItems={filterSellableItems}
onClickAddNewRow={handleClickAddNewRow} onClickAddNewRow={handleClickAddNewRow}
onClickClearAllLines={handleClearAllLines} onClickClearAllLines={handleClearAllLines}
onClickRemoveRow={handleClickRemoveLine} onClickRemoveRow={handleClickRemoveLine}

View File

@@ -91,6 +91,8 @@ function ItemsEntriesTable({
onClickRemoveRow, onClickRemoveRow,
onClickAddNewRow, onClickAddNewRow,
onClickClearAllLines, onClickClearAllLines,
filterPurchasableItems = false,
filterSellableItems = false,
}) { }) {
const [rows, setRows] = useState([]); const [rows, setRows] = useState([]);
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
@@ -117,6 +119,8 @@ function ItemsEntriesTable({
Cell: ItemsListCell, Cell: ItemsListCell,
disableSortBy: true, disableSortBy: true,
width: 180, width: 180,
filterPurchasable: filterPurchasableItems,
filterSellable: filterSellableItems,
}, },
{ {
Header: formatMessage({ id: 'description' }), Header: formatMessage({ id: 'description' }),

View File

@@ -33,7 +33,7 @@ const defaultInitialValues = {
active: true, active: true,
name: '', name: '',
type: 'service', type: 'service',
sku: '', code: '',
cost_price: '', cost_price: '',
sell_price: '', sell_price: '',
cost_account_id: '', cost_account_id: '',

View File

@@ -1,4 +1,5 @@
import * as Yup from 'yup'; import * as Yup from 'yup';
import { defaultTo } from 'lodash';
import { formatMessage } from 'services/intl'; import { formatMessage } from 'services/intl';
import { DATATYPES_LENGTH } from 'common/dataTypes'; import { DATATYPES_LENGTH } from 'common/dataTypes';
@@ -15,7 +16,7 @@ const Schema = Yup.object().shape({
.min(0) .min(0)
.max(DATATYPES_LENGTH.STRING) .max(DATATYPES_LENGTH.STRING)
.label(formatMessage({ id: 'item_type_' })), .label(formatMessage({ id: 'item_type_' })),
sku: Yup.string().trim().min(0).max(DATATYPES_LENGTH.STRING), code: Yup.string().trim().min(0).max(DATATYPES_LENGTH.STRING),
cost_price: Yup.number().when(['purchasable'], { cost_price: Yup.number().when(['purchasable'], {
is: true, is: true,
then: Yup.number() then: Yup.number()
@@ -61,8 +62,8 @@ const Schema = Yup.object().shape({
export const transformItemFormData = (item, defaultValue) => { export const transformItemFormData = (item, defaultValue) => {
return { return {
...item, ...item,
sellable: item?.sellable ? Boolean(item.sellable) : defaultValue.sellable, sellable: !!defaultTo(item?.sellable, defaultValue.sellable),
purchasable: item?.purchasable ? Boolean(item.purchasable) : defaultValue.purchasable, purchasable: !!defaultTo(item?.purchasable, defaultValue.purchasable),
}; };
} }

View File

@@ -27,7 +27,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
<Col xs={6}> <Col xs={6}>
{/*------------- Purchasable checbox ------------- */} {/*------------- Purchasable checbox ------------- */}
<FastField name={'sellable'} type="checkbox"> <FastField name={'sellable'} type="checkbox">
{({ field }) => ( {({ form, field }) => (
<FormGroup inline={true} className={'form-group--sellable'}> <FormGroup inline={true} className={'form-group--sellable'}>
<Checkbox <Checkbox
inline={true} inline={true}
@@ -44,7 +44,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
</FastField> </FastField>
{/*------------- Selling price ------------- */} {/*------------- Selling price ------------- */}
<Field name={'sell_price'}> <FastField name={'sell_price'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'selling_price'} />} label={<T id={'selling_price'} />}
@@ -67,7 +67,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
</ControlGroup> </ControlGroup>
</FormGroup> </FormGroup>
)} )}
</Field> </FastField>
{/*------------- Selling account ------------- */} {/*------------- Selling account ------------- */}
<FastField name={'sell_account_id'}> <FastField name={'sell_account_id'}>
@@ -93,6 +93,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
selectedAccountId={value} selectedAccountId={value}
disabled={!form.values.sellable} disabled={!form.values.sellable}
filterByTypes={['income']} filterByTypes={['income']}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}
@@ -118,7 +119,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
</FastField> </FastField>
{/*------------- Cost price ------------- */} {/*------------- Cost price ------------- */}
<Field name={'cost_price'}> <FastField name={'cost_price'}>
{({ field, form, field: { value }, meta: { error, touched } }) => ( {({ field, form, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'cost_price'} />} label={<T id={'cost_price'} />}
@@ -141,7 +142,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
</ControlGroup> </ControlGroup>
</FormGroup> </FormGroup>
)} )}
</Field> </FastField>
{/*------------- Cost account ------------- */} {/*------------- Cost account ------------- */}
<FastField name={'cost_account_id'}> <FastField name={'cost_account_id'}>
@@ -167,6 +168,7 @@ function ItemFormBody({ accountsList, baseCurrency }) {
selectedAccountId={value} selectedAccountId={value}
disabled={!form.values.purchasable} disabled={!form.values.purchasable}
filterByTypes={['cost_of_goods_sold']} filterByTypes={['cost_of_goods_sold']}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -135,7 +135,7 @@ function ItemFormPrimarySection({
</FastField> </FastField>
{/*----------- Item category ----------*/} {/*----------- Item category ----------*/}
<FastField name={'type'}> <FastField name={'category_id'}>
{({ form, field: { value }, meta: { error, touched } }) => ( {({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'category'} />} label={<T id={'category'} />}
@@ -143,7 +143,6 @@ function ItemFormPrimarySection({
intent={inputIntent({ error, touched })} intent={inputIntent({ error, touched })}
helperText={<ErrorMessage name="category_id" />} helperText={<ErrorMessage name="category_id" />}
className={classNames( className={classNames(
'form-group--select-list',
'form-group--category', 'form-group--category',
Classes.FILL, Classes.FILL,
)} )}
@@ -154,7 +153,6 @@ function ItemFormPrimarySection({
onCategorySelected={(category) => { onCategorySelected={(category) => {
form.setFieldValue('category_id', category.id); form.setFieldValue('category_id', category.id);
}} }}
popoverProps={{ minimal: true }}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -111,8 +111,8 @@ function ItemsDataTable({
}, },
{ {
Header: formatMessage({ id: 'item_code' }), Header: formatMessage({ id: 'item_code' }),
accessor: 'sku', accessor: 'code',
className: 'sku', className: 'code',
width: 120, width: 120,
}, },
{ {

View File

@@ -22,7 +22,7 @@ import withBillDetail from './withBillDetail';
import { AppToaster } from 'components'; import { AppToaster } from 'components';
import { ERROR } from 'common/errors'; import { ERROR } from 'common/errors';
import { compose, repeatValue, orderingLinesIndexes } from 'utils'; import { compose, repeatValue, defaultToTransform, orderingLinesIndexes } from 'utils';
const MIN_LINES_NUMBER = 5; const MIN_LINES_NUMBER = 5;
@@ -207,7 +207,10 @@ function BillForm({
{({ isSubmitting, values }) => ( {({ isSubmitting, values }) => (
<Form> <Form>
<BillFormHeader onBillNumberChanged={handleBillNumberChanged} /> <BillFormHeader onBillNumberChanged={handleBillNumberChanged} />
<EditableItemsEntriesTable defaultEntry={defaultBill} /> <EditableItemsEntriesTable
defaultEntry={defaultBill}
filterPurchasableItems={true}
/>
<BillFormFooter <BillFormFooter
oninitialFiles={[]} oninitialFiles={[]}
// onDropFiles={handleDeleteFile} // onDropFiles={handleDeleteFile}

View File

@@ -54,6 +54,7 @@ function BillFormHeader({
onContactSelected={(contact) => { onContactSelected={(contact) => {
form.setFieldValue('vendor_id', contact.id); form.setFieldValue('vendor_id', contact.id);
}} }}
popoverFill={true}
/> />
</FormGroup> </FormGroup>
)} )}

View File

@@ -9,14 +9,6 @@ import * as serviceWorker from 'serviceWorker';
import { store, persistor } from 'store/createStore'; import { store, persistor } from 'store/createStore';
import AppProgress from 'components/NProgress/AppProgress'; import AppProgress from 'components/NProgress/AppProgress';
import whyDidYouRender from '@welldone-software/why-did-you-render';
whyDidYouRender(React, {
onlyLogs: true,
titleColor: 'green',
diffNameColor: 'aqua',
});
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<PersistGate loading={null} persistor={persistor}> <PersistGate loading={null} persistor={persistor}>

View File

@@ -259,7 +259,6 @@ export default [
}), }),
breadcrumb: 'Edit', breadcrumb: 'Edit',
}, },
{ {
path: `/invoices/new`, path: `/invoices/new`,
component: LazyLoader({ component: LazyLoader({
@@ -298,10 +297,9 @@ export default [
breadcrumb: 'Receipt List', breadcrumb: 'Receipt List',
}, },
// Payment Receives // Payment receives
{ {
path: `/payment-receive/:id/edit`, path: `/payment-receives/:id/edit`,
component: LazyLoader({ component: LazyLoader({
loader: () => loader: () =>
import('containers/Sales/PaymentReceive/PaymentReceiveFormPage'), import('containers/Sales/PaymentReceive/PaymentReceiveFormPage'),
@@ -309,7 +307,7 @@ export default [
breadcrumb: 'Edit', breadcrumb: 'Edit',
}, },
{ {
path: `/payment-receive/new`, path: `/payment-receives/new`,
component: LazyLoader({ component: LazyLoader({
loader: () => loader: () =>
import('containers/Sales/PaymentReceive/PaymentReceiveFormPage'), import('containers/Sales/PaymentReceive/PaymentReceiveFormPage'),
@@ -364,14 +362,14 @@ export default [
}, },
// Payment mades. // Payment mades.
{ {
path: `/payment-made/:id/edit`, path: `/payment-mades/:id/edit`,
component: LazyLoader({ component: LazyLoader({
loader: () => import('containers/Purchases/PaymentMades/PaymentMade'), loader: () => import('containers/Purchases/PaymentMades/PaymentMade'),
}), }),
breadcrumb: 'Edit', breadcrumb: 'Edit',
}, },
{ {
path: `/payment-made/new`, path: `/payment-mades/new`,
component: LazyLoader({ component: LazyLoader({
loader: () => import('containers/Purchases/PaymentMades/PaymentMade'), loader: () => import('containers/Purchases/PaymentMades/PaymentMade'),
}), }),

View File

@@ -81,7 +81,7 @@ export default class ItemsController extends BaseController {
check('name').exists(), check('name').exists(),
check('type').exists().trim().escape() check('type').exists().trim().escape()
.isIn(['service', 'non-inventory', 'inventory']), .isIn(['service', 'non-inventory', 'inventory']),
check('sku').optional({ nullable: true }).trim().escape(), check('code').optional({ nullable: true }).trim().escape(),
// Purchase attributes. // Purchase attributes.
check('purchasable').optional().isBoolean().toBoolean(), check('purchasable').optional().isBoolean().toBoolean(),
check('cost_price') check('cost_price')

View File

@@ -4,7 +4,7 @@ exports.up = function (knex) {
table.increments(); table.increments();
table.string('name').index(); table.string('name').index();
table.string('type').index(); table.string('type').index();
table.string('sku'); table.string('code');
table.boolean('sellable').index(); table.boolean('sellable').index();
table.boolean('purchasable').index(); table.boolean('purchasable').index();
table.decimal('sell_price', 13, 3).unsigned(); table.decimal('sell_price', 13, 3).unsigned();

View File

@@ -8,7 +8,7 @@ exports.up = function(knex) {
table.decimal('amount', 13, 3).defaultTo(0); table.decimal('amount', 13, 3).defaultTo(0);
table.string('reference_no').index(); table.string('reference_no').index();
table.integer('deposit_account_id').unsigned().references('id').inTable('accounts'); table.integer('deposit_account_id').unsigned().references('id').inTable('accounts');
table.string('payment_receive_no'); table.string('payment_receive_no').nullable();
table.text('description'); table.text('description');
table.integer('user_id').unsigned().index(); table.integer('user_id').unsigned().index();
table.timestamps(); table.timestamps();

View File

@@ -4,7 +4,7 @@ exports.up = function(knex) {
table.increments(); table.increments();
table.integer('payment_receive_id').unsigned().index().references('id').inTable('payment_receives'); table.integer('payment_receive_id').unsigned().index().references('id').inTable('payment_receives');
table.integer('invoice_id').unsigned().index().references('id').inTable('sales_invoices'); table.integer('invoice_id').unsigned().index().references('id').inTable('sales_invoices');
table.decimal('payment_amount').unsigned(); table.decimal('payment_amount', 13, 3).unsigned();
}) })
}; };

View File

@@ -5,7 +5,7 @@ exports.up = function(knex) {
table.integer('vendor_id').unsigned().index().references('id').inTable('contacts'); table.integer('vendor_id').unsigned().index().references('id').inTable('contacts');
table.decimal('amount', 13, 3).defaultTo(0); table.decimal('amount', 13, 3).defaultTo(0);
table.integer('payment_account_id').unsigned().references('id').inTable('accounts'); table.integer('payment_account_id').unsigned().references('id').inTable('accounts');
table.string('payment_number').index(); table.string('payment_number').nullable().index();
table.date('payment_date').index(); table.date('payment_date').index();
table.string('payment_method'); table.string('payment_method');
table.string('reference'); table.string('reference');

View File

@@ -4,7 +4,7 @@ export interface IItem{
id: number, id: number,
name: string, name: string,
type: string, type: string,
sku: string, code: string,
sellable: boolean, sellable: boolean,
purchasable: boolean, purchasable: boolean,
@@ -33,7 +33,7 @@ export interface IItem{
export interface IItemDTO { export interface IItemDTO {
name: string, name: string,
type: string, type: string,
sku: string, code: string,
sellable: boolean, sellable: boolean,
purchasable: boolean, purchasable: boolean,