Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion changelogs/unreleased/103618_CD.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Customer deliveries: add managament of alternatives barcodes on line search",
"title": "Customer deliveries: add management of alternatives barcodes on line search",
"type": "feat",
"packages": "stock"
}
2 changes: 1 addition & 1 deletion changelogs/unreleased/103618_IM.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Internal moves: add managament of alternatives barcodes on line search",
"title": "Internal moves: add management of alternatives barcodes on line search",
"type": "feat",
"packages": "stock"
}
2 changes: 1 addition & 1 deletion changelogs/unreleased/103618_Inv.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Inventories: add managament of alternatives barcodes on line search",
"title": "Inventories: add management of alternatives barcodes on line search",
"type": "feat",
"packages": "stock"
}
2 changes: 1 addition & 1 deletion changelogs/unreleased/103618_SA.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Supplier arrivals: add managament of alternatives barcodes on line search",
"title": "Supplier arrivals: add management of alternatives barcodes on line search",
"type": "feat",
"packages": "stock"
}
2 changes: 1 addition & 1 deletion changelogs/unreleased/103618_picking.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"title": "Mass picking: add managament of alternatives barcodes on line/product search",
"title": "Mass picking: add management of alternatives barcodes on line/product search",
"type": "feat",
"packages": "stock"
}
5 changes: 5 additions & 0 deletions changelogs/unreleased/105017.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Control entries: add quick access from operation order view",
"type": "feat",
"packages": "quality"
}
5 changes: 5 additions & 0 deletions changelogs/unreleased/105017_core.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"title": "Global tools: allow use of async function to define hideIf condition",
"type": "feat",
"packages": "core"
}
24 changes: 24 additions & 0 deletions packages/apps/quality/src/api/control-entry-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const createControlEntryCriteria = (
userId,
date,
selectedStatus,
relatedToSelect,
relatedToSelectId,
) => {
const criteria = [getSearchCriterias('quality_controlEntry', searchValue)];

Expand Down Expand Up @@ -68,6 +70,24 @@ const createControlEntryCriteria = (
);
}

if (relatedToSelect && relatedToSelectId) {
criteria.push({
operator: 'and',
criteria: [
{
fieldName: 'relatedToSelect',
operator: '=',
value: relatedToSelect,
},
{
fieldName: 'relatedToSelectId',
operator: '=',
value: relatedToSelectId,
},
],
});
}

return criteria;
};

Expand All @@ -79,6 +99,8 @@ export async function searchControlEntry({
date = null,
selectedStatus = null,
filterDomain,
relatedToSelect,
relatedToSelectId,
}) {
return createStandardSearch({
model: 'com.axelor.apps.quality.db.ControlEntry',
Expand All @@ -88,6 +110,8 @@ export async function searchControlEntry({
userId,
date,
selectedStatus,
relatedToSelect,
relatedToSelectId,
),
fieldKey: 'quality_controlEntry',
sortKey: 'quality_controlEntry',
Expand Down
1 change: 1 addition & 0 deletions packages/apps/quality/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"Quality_Send": "Send",
"Quality_DeclareNonConformity": "Declare non-conformity",
"Quality_SeeAttachedFiles": "See attached files",
"Quality_CheckControlEntries": "Check control entries",
"Quality_SliceAction_SearchControlEntry": "search control entries",
"Quality_SliceAction_FetchControlEntryById": "fetch control entry by id",
"Quality_SliceAction_SearchControlEntrySample": "search control entry samples",
Expand Down
1 change: 1 addition & 0 deletions packages/apps/quality/src/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"Quality_Send": "Envoyer",
"Quality_DeclareNonConformity": "Déclarer une non-conformité",
"Quality_SeeAttachedFiles": "Voir les fichiers joints",
"Quality_CheckControlEntries": "Accéder aux relevés de contrôle",
"Quality_SliceAction_SearchControlEntry": "recherche des relevés de contrôle",
"Quality_SliceAction_FetchControlEntryById": "récupération du relevé de contrôle par id",
"Quality_SliceAction_SearchControlEntrySample": "recherche sur les échantillons du relevé de contôle",
Expand Down
80 changes: 60 additions & 20 deletions packages/apps/quality/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ import {
} from './models';
import * as qualityReducers from './features';
import {useQualityHeaders} from './hooks/use-quality-header-actions';
import {searchControlEntry} from './api/control-entry-api';

const MODELS = {
STOCK_MOVE: 'com.axelor.apps.stock.db.StockMove',
STOCK_MOVE_LINE: 'com.axelor.apps.stock.db.StockMoveLine',
MANUFACTURING_ORDER: 'com.axelor.apps.production.db.ManufOrder',
OPERATION_ORDER: 'com.axelor.apps.production.db.OperationOrder',
};

export const QualityModule: Module = {
name: 'app-quality',
Expand Down Expand Up @@ -83,29 +91,61 @@ export const QualityModule: Module = {
iconName: 'clipboard2-x',
onPress: ({navigation, screenContext}) =>
navigation.navigate('QualityImprovementFormScreen', {
stockMoveId: getModelId(
screenContext,
'com.axelor.apps.stock.db.StockMove',
),
stockMoveLineId: getModelId(
screenContext,
'com.axelor.apps.stock.db.StockMoveLine',
),
manufOrderId: getModelId(
screenContext,
'com.axelor.apps.production.db.ManufOrder',
),
operationOrderId: getModelId(
screenContext,
'com.axelor.apps.production.db.OperationOrder',
),
stockMoveId: getModelId(screenContext, MODELS.STOCK_MOVE),
stockMoveLineId: getModelId(screenContext, MODELS.STOCK_MOVE_LINE),
manufOrderId: getModelId(screenContext, MODELS.MANUFACTURING_ORDER),
operationOrderId: getModelId(screenContext, MODELS.OPERATION_ORDER),
}),
title: 'Quality_DeclareNonConformity',
hideIf: ({screenContext}) =>
!isModel(screenContext, 'com.axelor.apps.stock.db.StockMove') &&
!isModel(screenContext, 'com.axelor.apps.stock.db.StockMoveLine') &&
!isModel(screenContext, 'com.axelor.apps.production.db.ManufOrder') &&
!isModel(screenContext, 'com.axelor.apps.production.db.OperationOrder'),
!isModel(screenContext, MODELS.STOCK_MOVE) &&
!isModel(screenContext, MODELS.STOCK_MOVE_LINE) &&
!isModel(screenContext, MODELS.MANUFACTURING_ORDER) &&
!isModel(screenContext, MODELS.OPERATION_ORDER),
},
{
key: 'quality_accessControlEntry',
iconName: 'card-checklist',
onPress: async ({navigation, screenContext}) => {
const _controlEntryList = await searchControlEntry({
relatedToSelect: MODELS.OPERATION_ORDER,
relatedToSelectId: getModelId(screenContext, MODELS.OPERATION_ORDER),
} as any)
.then(res => res?.data?.data)
.catch(() => []);

if (_controlEntryList?.length === 1) {
navigation.navigate('ControlEntryDetailsScreen', {
controlEntryId: _controlEntryList[0].id,
});
} else {
navigation.navigate('ControlEntryListScreen', {
relatedToSelect: MODELS.OPERATION_ORDER,
relatedToSelectId: getModelId(
screenContext,
MODELS.OPERATION_ORDER,
),
});
}
},
title: 'Quality_CheckControlEntries',
hideIf: async ({screenContext}) => {
const _isOperationModel = isModel(
screenContext,
MODELS.OPERATION_ORDER,
);

if (!_isOperationModel) return true;

const _controlEntryList = await searchControlEntry({
relatedToSelect: MODELS.OPERATION_ORDER,
relatedToSelectId: getModelId(screenContext, MODELS.OPERATION_ORDER),
} as any)
.then(res => res?.data?.data ?? [])
.catch(() => []);

return _controlEntryList?.length === 0;
},
},
],
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import {
import {searchControlEntry} from '../../features/controlEntrySlice';
import {ControlEntryCard} from '../../components';

const ControlEntryListScreen = ({navigation}) => {
const ControlEntryListScreen = ({navigation, route}) => {
const {relatedToSelect, relatedToSelectId} = route?.params ?? {};
const I18n = useTranslator();
const dispatch = useDispatch();
const {ControlEntry} = useTypes();
Expand All @@ -57,29 +58,34 @@ const ControlEntryListScreen = ({navigation}) => {
[ControlEntry?.statusSelect, getSelectionItems, selectedStatus],
);

const fetchControlEntryAPI = useCallback(
(page = 0) => {
dispatch(
searchControlEntry({
page: page,
isInspector: isInspectorFilter,
userId: userId,
date: dateFilter,
selectedStatus: selectedStatus,
filterDomain: activeFilter,
}),
);
},
const sliceFunctionData = useMemo(
() => ({
isInspector: isInspectorFilter,
userId,
date: dateFilter,
selectedStatus,
filterDomain: activeFilter,
relatedToSelect,
relatedToSelectId,
}),
[
activeFilter,
dateFilter,
dispatch,
isInspectorFilter,
relatedToSelect,
relatedToSelectId,
selectedStatus,
userId,
],
);

const fetchControlEntryAPI = useCallback(
(page = 0) => {
dispatch((searchControlEntry as any)({page, ...sliceFunctionData}));
},
[dispatch, sliceFunctionData],
);

return (
<Screen removeSpaceOnTop={true}>
<FilterContainer
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/app/modules/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ export interface Tool {
title?: string;
iconName: string;
color?: string;
hideIf?: (data: ToolData) => boolean;
hideIf?: (data: ToolData) => boolean | Promise<boolean>;
disabledIf?: (data: ToolData) => boolean;
onPress: (data: ActionToolData) => void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import React, {useMemo} from 'react';
import React, {useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
import {
DraggableWrapper,
Expand All @@ -40,20 +40,44 @@ const GlobalToolBox = () => {
const storeState = useSelector(state => state);
const {token} = useSelector(state => state.auth);

const visibleActions = useMemo(() => {
const data = {dispatch, storeState, screenContext: context};
const [visibleActions, setVisibleActions] = useState([]);

return modulesActions
.filter(_a => !_a.hideIf(data))
.sort((a, b) => a.order - b.order)
.map(_a => ({
key: _a.key,
title: _a.title,
color: Colors[_a.color],
iconName: _a.iconName,
disabled: _a.disabledIf(data),
onPress: () => _a.onPress({...data, navigation, translator: I18n.t}),
}));
useEffect(() => {
let isMounted = true;

async function computeActions() {
const data = {dispatch, storeState, screenContext: context};

const results = await Promise.all(
modulesActions.map(async action => {
const shouldHide = await action.hideIf?.(data);
return {action, shouldHide};
}),
);

const visible = results
.filter(r => !r.shouldHide)
.map(r => r.action)
.sort((a, b) => a.order - b.order)
.map(_a => ({
key: _a.key,
title: _a.title,
color: Colors[_a.color],
iconName: _a.iconName,
disabled: _a.disabledIf(data),
onPress: () => _a.onPress({...data, navigation, translator: I18n.t}),
}));

if (isMounted) {
setVisibleActions(visible);
}
}

computeActions();

return () => {
isMounted = false;
};
}, [
Colors,
I18n.t,
Expand Down