diff --git a/.env.example b/.env.example index 312d326c..98c2e210 100644 --- a/.env.example +++ b/.env.example @@ -5,8 +5,9 @@ VUE_APP_VIEW_SIZE=10 VUE_APP_DATE_FORMAT=MM/dd/yyyy VUE_APP_PERMISSION_ID="IMPORT_APP_VIEW" VUE_APP_ALIAS={} -VUE_APP_MAPPING_TYPES={"PO": "PO_MAPPING_PREF","RSTINV": "INV_MAPPING_PREF"} +VUE_APP_MAPPING_TYPES={"PO": "PO_MAPPING_PREF","RSTINV": "INV_MAPPING_PREF","RSTSTK": "STK_MAPPING_PREF"} VUE_APP_MAPPING_PO={"orderId": { "label": "Order ID", "required": true }, "productSku": { "label": "Shopify product SKU", "required": true },"orderDate": { "label": "Arrival date", "required": true }, "quantity": { "label": "Ordered quantity", "required": true }, "facility": { "label": "Facility ID", "required": true }} VUE_APP_MAPPING_RSTINV={"productIdentification": { "label": "Product Identification", "required": true }, "quantity": { "label": "Quantity", "required": true }, "facility": { "label": "Facility ID", "required": true }} +VUE_APP_MAPPING_RSTSTK={"productIdentification": { "label": "Product Identification", "required": true }, "restockQuantity": { "label": "Restock quantity", "required": true }} VUE_APP_DEFAULT_LOG_LEVEL="error" VUE_APP_LOGIN_URL="http://launchpad.hotwax.io/login" \ No newline at end of file diff --git a/src/components/Menu.vue b/src/components/Menu.vue index e4c25814..24697b3f 100644 --- a/src/components/Menu.vue +++ b/src/components/Menu.vue @@ -52,7 +52,7 @@ import { } from "@ionic/vue"; import { computed, defineComponent } from "vue"; import { mapGetters } from "vuex"; -import { albumsOutline, bookmarkOutline, settings, calendar } from "ionicons/icons"; +import { albumsOutline, bookmarkOutline, settings, calendar, timerOutline } from "ionicons/icons"; import { useStore } from "@/store"; import { useRouter } from "vue-router"; import { translate } from '@hotwax/dxp-components' @@ -91,6 +91,13 @@ export default defineComponent({ iosIcon: albumsOutline, mdIcon: albumsOutline }, + { + title: "Scheduled restock", + url: "/scheduled-restock", + childRoutes: ["/scheduled-restock-review"], + iosIcon: timerOutline, + mdIcon: timerOutline + }, { title: "Purchase order", url: "/purchase-order", @@ -125,7 +132,8 @@ export default defineComponent({ calendar, settings, store, - translate + translate, + timerOutline }; } }); diff --git a/src/components/ScheduledRestockPopover.vue b/src/components/ScheduledRestockPopover.vue new file mode 100644 index 00000000..40193b93 --- /dev/null +++ b/src/components/ScheduledRestockPopover.vue @@ -0,0 +1,147 @@ + + + \ No newline at end of file diff --git a/src/locales/en.json b/src/locales/en.json index 096004e4..9909b699 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -28,6 +28,7 @@ "Click the backdrop to dismiss.": "Click the backdrop to dismiss.", "Completed": "Completed", "Confirm": "Confirm", + "Configuration missing": "Configuration missing", "CSV input": "CSV input", "CSV Mapping": "CSV Mapping", "Custom date format": "Custom date format", @@ -44,9 +45,13 @@ "Expected input": "Expected input", "Enter product sku to search": "Enter product sku to search", "Facility": "Facility", + "Facility not found": "Facility not found", + "Facilities": "Facilities", "Facility ID": "Facility ID", "Facility Location": "Facility Location", "Failed to save CSV mapping.": "Failed to save CSV mapping.", + "Failed to schedule job": "Failed to schedule job", + "Failed to cancel job": "Failed to cancel job", "Failed to delete CSV mapping.": "Failed to delete CSV mapping.", "Failed to update CSV mapping.": "Failed to update CSV mapping.", "Fetching TimeZones": "Fetching TimeZones", @@ -93,12 +98,14 @@ "New version available, please update the app.": "New version available, please update the app.", "There are no saved CSV mappings to show. Create a new mapping from a file upload screen": "There are no saved CSV mappings to show. Create a new mapping from a file upload screen", "No new file upload. Please try again": "No new file upload. Please try again", + "No products found": "No products found", "No results found": "No results found", "No time zone found": "No time zone found", "of": "of", "OMS": "OMS", "OMS instance": "OMS instance", "Only select": "Only select", + "Optional, or select during review": "Optional, or select during review", "Order buffer": "Order buffer", "Order ID": "Order ID", "Ordered": "Ordered", @@ -107,17 +114,24 @@ "Password": "Password", "Pending": "Pending", "Please ensure that the uploaded file contains accurate product information. If a product does not exist, the corresponding records will not be processed.": "Please ensure that the uploaded file contains accurate product information. If a product does not exist, the corresponding records will not be processed.", + "Please provide a future date and time": "Please provide a future date and time", + "Please select a facility": "Please select a facility", + "Please select a schedule time": "Please select a schedule time", + "Please select a product store": "Please select a product store", + "Please select a shopify shop": "Please select a shopify shop", "Please upload a valid purchase order csv to continue": "Please upload a valid purchase order csv to continue", "Please upload a valid reset inventory csv to continue": "Please upload a valid reset inventory csv to continue", "PO External Order ID": "PO External Order ID", "Preorder": "Preorder", "Product Identification": "Product Identification", "Product SKU": "Product SKU", + "Product store": "Product store", "Product not found": "Product not found", "Purchase order": "Purchase order", "Purchase orders": "Purchase orders", "Quantity": "Quantity", "Ready to create an app?": "Ready to create an app?", + "Restock quantity": "Restock quantity", "Review": "Review", "Review PO details": "Review PO details", "Review purchase order": "Review purchase order", @@ -125,7 +139,12 @@ "Reset": "Reset", "Reset inventory": "Reset inventory", "Reset password": "Reset password", + "Restock": "Restock", + "Restock name": "Restock name", + "Restock details": "Restock details", "Results": "Results", + "Reschedule": "Reschedule", + "Required": "Required", "Safety stock": "Safety stock", "Save mapping": "Save mapping", "Sample": "Sample", @@ -136,12 +155,18 @@ "Search products": "Search products", "Search time zones": "Search time zones", "Seems like uploaded file has missing products, checked with initial records.": "Seems like uploaded file has missing products, checked with initial {initialCount} records.", + "Schedule": "Schedule", "Select": "Select", "Select mapping": "Select mapping", "Select SKU": "Select SKU", "Select all the fields to continue": "Select all the fields to continue", "Select time zone": "Select time zone", + "Select time": "Select time", "Select the column index for the following information in the uploaded CSV.": "Select the column index for the following information in the uploaded CSV.", + "Service updated successfully": "Service updated successfully", + "Service has been scheduled": "Service has been scheduled", + "Scheduled Restock": "Scheduled Restock", + "Shopify store": "Shopify store", "Some of the mapping fields are missing in the CSV: ": "Some of the mapping fields are missing in the CSV: {missingFields}", "Changes have been successfully applied. Some of the selected items have quantity less than or equal to order buffer. The quantity of those items is set to 1.": "Changes have been successfully applied. {newLine} Some of the selected items have quantity less than or equal to order buffer. The quantity of those items is set to 1.", "Something went wrong": "Something went wrong", diff --git a/src/router/index.ts b/src/router/index.ts index ad4bc2ad..caa8eadc 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -6,6 +6,8 @@ import InventoryReview from '@/views/InventoryReview.vue' import PurchaseOrderReview from '@/views/PurchaseOrderReview.vue'; import SavedMappings from '@/views/SavedMappings.vue' import Settings from "@/views/Settings.vue" +import ScheduledRestock from "@/views/ScheduledRestock.vue"; +import ScheduledRestockReview from "@/views/ScheduledRestockReview.vue" import store from '@/store' import MappingDetail from '@/views/MappingDetail.vue' import { DxpLogin, translate, useAuthStore } from '@hotwax/dxp-components'; @@ -72,6 +74,18 @@ const routes: Array = [ component: InventoryReview, beforeEnter: authGuard }, + { + path: '/scheduled-restock', + name: 'ScheduledRestock', + component: ScheduledRestock, + beforeEnter: authGuard + }, + { + path: '/scheduled-restock-review', + name: 'ScheduledRestockReview', + component: ScheduledRestockReview, + beforeEnter: authGuard + }, { path: '/login', name: 'Login', diff --git a/src/services/StockService.ts b/src/services/StockService.ts new file mode 100644 index 00000000..453ba906 --- /dev/null +++ b/src/services/StockService.ts @@ -0,0 +1,40 @@ +import { api } from '@/adapter'; + +const scheduleJob = async (payload: any): Promise => { + return api({ + url: "scheduleService", + method: "post", + data: payload + }); +} + +const fetchJobInformation = async (payload: any): Promise => { + return api({ + url: "/findJobs", + method: "get", + params: payload + }); +} + +const updateJob = async (payload: any): Promise => { + return api({ + url: "service/updateJobSandbox", + method: "post", + data: payload + }); +} + +const cancelJob = async (payload: any): Promise => { + return api({ + url: "service/cancelScheduledJob", + method: "post", + data: payload + }); +} + +export const StockService = { + cancelJob, + scheduleJob, + fetchJobInformation, + updateJob +} \ No newline at end of file diff --git a/src/services/UploadService.ts b/src/services/UploadService.ts index 2b786504..f83fbe3c 100644 --- a/src/services/UploadService.ts +++ b/src/services/UploadService.ts @@ -17,6 +17,14 @@ const uploadAndImportFile = async (payload: any): Promise => { }); } +const createIncomingShipment = async (payload: any): Promise => { + return api({ + url: "/service/createIncomingShipment", + method: "post", + data: payload + }); +} + const prepareUploadJsonPayload = (request: UploadRequest) => { const blob = new Blob([JSON.stringify(request.uploadData)], { type: 'application/json'}); const formData = new FormData(); @@ -38,5 +46,6 @@ const prepareUploadJsonPayload = (request: UploadRequest) => { export const UploadService = { prepareUploadJsonPayload, uploadAndImportFile, - uploadJsonFile + uploadJsonFile, + createIncomingShipment } \ No newline at end of file diff --git a/src/services/UtilService.ts b/src/services/UtilService.ts index 5c65c4df..dede225a 100644 --- a/src/services/UtilService.ts +++ b/src/services/UtilService.ts @@ -25,8 +25,26 @@ const fetchGoodIdentificationTypes = async (payload: any): Promise => { }) } +const fetchShopifyShop = async (payload: any): Promise => { + return api({ + url: "/performFind", + method: "POST", + data: payload + }) +} + +const fetchProductStores = async (payload: any): Promise => { + return api({ + url: "/performFind", + method: "POST", + data: payload + }) +} + export const UtilService = { fetchGoodIdentificationTypes, + fetchShopifyShop, getFacilities, - getFacilityLocations + getFacilityLocations, + fetchProductStores } \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index b05f7e7d..98c0a335 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -22,7 +22,7 @@ const state: any = { } const persistState = createPersistedState({ - paths: ['user'], + paths: ['user', 'util.productStores'], fetchBeforeUse: true }) diff --git a/src/store/modules/stock/StockState.ts b/src/store/modules/stock/StockState.ts index fee226ff..02cbf589 100644 --- a/src/store/modules/stock/StockState.ts +++ b/src/store/modules/stock/StockState.ts @@ -5,5 +5,15 @@ export default interface StockState { unidentifiedItems: any, initial: any, }, - fileName: string + fileName: string, + restockItems: [], + schedule: { + scheduledTime: any, + shopId: any, + restockName: any , + productStoreId: any, + facilityId: any + } + shopifyShops: any, + jobs: any } diff --git a/src/store/modules/stock/actions.ts b/src/store/modules/stock/actions.ts index 324ba61f..fc16d606 100644 --- a/src/store/modules/stock/actions.ts +++ b/src/store/modules/stock/actions.ts @@ -3,6 +3,12 @@ import store from '@/store' import RootState from '@/store/RootState' import StockState from './StockState' import * as types from './mutation-types' +import { showToast } from '@/utils'; +import { hasError } from "@/adapter"; +import { StockService } from "@/services/StockService"; +import { translate } from "@hotwax/dxp-components"; +import logger from "@/logger"; +import { DateTime } from 'luxon' const actions: ActionTree = { async processUpdateStockItems ({ commit, rootGetters }, items) { @@ -11,7 +17,6 @@ const actions: ActionTree = { //Fetching only top const productIds = items.slice(0, process.env['VUE_APP_VIEW_SIZE']).map((item: any) => item.identification); - // We are getting external facilityId from CSV, extract facilityId and pass for getting locations const externalFacilityIds = [...new Set(items.map((item: any) => item.externalFacilityId))] const facilities = await store.dispatch('util/fetchFacilities'); @@ -24,7 +29,6 @@ const actions: ActionTree = { }).filter((facilityId: any) => facilityId) store.dispatch('util/fetchFacilityLocations', facilityIds); - const viewSize = productIds.length; const viewIndex = 0; const payload = { @@ -53,7 +57,6 @@ const actions: ActionTree = { }).filter((item: any) => item); const original = JSON.parse(JSON.stringify(items)); - commit(types.STOCK_ITEMS_UPDATED, { parsed, original, initial }); this.dispatch('util/updateFileProcessingStatus', false); }, @@ -63,6 +66,172 @@ const actions: ActionTree = { clearStockItems({ commit }){ commit(types.STOCK_ITEMS_UPDATED, { parsed: [], original: []}); }, + async processUpdateRestockItems({ commit }, items) { + + const productIds = items.map((item: any) => item.identification); + + const payload = { + productIds, + identificationTypeId: items[0]?.identificationTypeId + }; + + const cachedProducts = await store.dispatch("product/fetchProducts", payload); + // creating products object based on identification selected + const products: any = Object.values(cachedProducts).reduce((updatedProducts: any, product: any) => { + const identification = product.identifications.find((identification: any) => payload.identificationTypeId.toLowerCase() === identification.productIdTypeEnumId.toLowerCase()) + updatedProducts[identification.idValue] = product + return updatedProducts; + }, {}) + + const initial = items.map((item: any) => { + const product = products[item.identification]; + + if (product) { + item.parentProductId = product?.parent?.id; + item.pseudoId = product.pseudoId; + item.parentProductName = product?.parent?.productName; + item.productId = product.productId + item.imageUrl = product.images?.mainImageUrl; + item.isSelected = true; + return item; + } + return; + }).filter((item: any) => item); + + commit(types.STOCK_SCHEDULE_ITEMS_UPDATED, initial); + }, + async scheduledStock({ commit }, payload) { + commit(types.STOCK_SCHEDULED_INFORMATION, payload) + }, + async clearScheduledStock({ commit }) { + commit(types.STOCK_SCHEDULED_INFORMATION, { + scheduledTime: "", + shopId: "", + restockName: "", + productStoreId: "", + facilityId: "" + }) + }, + async shopifyShop({ commit }, payload) { + commit(types.STOCK_SHOPIFY_SHOPS_UPDATED, payload) + }, + + async scheduleService({ dispatch, state }, { params, restockName }) { + let resp; + + const job = await dispatch("fetchDraftJob") + + if(!job.jobId || !job.serviceName || job.serviceName == '_NA_') { + showToast(translate("Configuration missing")) + return; + } + + const payload = { + 'JOB_NAME': restockName || state.schedule.restockName || `Created ${DateTime.now().toLocaleString(DateTime.DATETIME_MED)}`, + 'SERVICE_NAME': job.serviceName, + 'SERVICE_COUNT': '0', + 'SERVICE_TEMP_EXPR': job.jobStatus, + 'SERVICE_RUN_AS_SYSTEM':'Y', + 'jobFields': { + 'systemJobEnumId': job.systemJobEnumId, + 'tempExprId': job.jobStatus, // Need to remove this as we are passing frequency in SERVICE_TEMP_EXPR, currently kept it for backward compatibility + 'parentJobId': job.parentJobId, + 'runAsUser': 'system', //default system, but empty in run now. TODO Need to remove this as we are using SERVICE_RUN_AS_SYSTEM, currently kept it for backward compatibility + 'recurrenceTimeZone': this.state.user.current.userTimeZone, + 'createdByUserLogin': this.state.user.current.userLoginId, + 'lastModifiedByUserLogin': this.state.user.current.userLoginId, + }, + 'statusId': "SERVICE_PENDING", + 'systemJobEnumId': job.systemJobEnumId, + ...params + } + + job?.priority && (payload['SERVICE_PRIORITY'] = job.priority.toString()) + payload['SERVICE_TIME'] = state.schedule.scheduledTime.toString() + job?.sinceId && (payload['sinceId'] = job.sinceId) + + try { + resp = await StockService.scheduleJob({ ...payload }); + if (resp.status == 200 && !hasError(resp)) { + showToast(translate('Service has been scheduled')); + } else { + showToast(translate('Something went wrong')) + } + } catch (err) { + showToast(translate('Something went wrong')) + logger.error(err) + } + return {}; + }, + + async fetchDraftJob() { + let resp, job: any = {}; + + const payload = { + "inputFields": { + "statusId": "SERVICE_DRAFT", + "statusId_op": "equals", + "systemJobEnumId": "JOB_SCHEDULED_RSTK", + "systemJobEnumId_op": "equals" + }, + "fieldList": [ "systemJobEnumId", "runTime", "tempExprId", "parentJobId", "serviceName", "jobId", "jobName", "currentRetryCount", "statusId", "runtimeDataId", "productStoreId", "priority"], + "noConditionFind": "Y", + "viewSize": 1, + "orderBy": "runTime ASC" + } + + try { + resp = await StockService.fetchJobInformation(payload) + + if(!hasError(resp) && resp.data.docs.length) { + job = resp.data.docs[0] + + job = { + ...job, + status: job.statusId, + enumId: job.systemJobEnumId, + frequency: job.tempExprId, + id: job.jobId + } + } else { + throw resp.data + } + } catch(err) { + logger.error('Failed to fetch draft job') + job = {} + } + + return job; + }, + + async fetchJobs ({ commit }) { + let resp; + + try{ + const params = { + "inputFields": { + "statusId": "SERVICE_PENDING", + 'systemJobEnumId': "JOB_SCHEDULED_RSTK", + 'systemJobEnumId_op': 'equals', + 'orderBy': 'runTime ASC' + }, + "noConditionFind": "Y", + "viewSize": 50 + } as any + + resp = await StockService.fetchJobInformation(params) + + if(!hasError(resp) && resp.data.count > 0) { + const jobs = resp.data.docs + commit(types.STOCK_JOBS_UPDATED, jobs); + } else { + commit(types.STOCK_JOBS_UPDATED, []); + } + } catch(error) { + logger.error(error); + } + return resp + }, async updateMissingFacilities({ state }, facilityMapping){ const facilityLocations = await this.dispatch('util/fetchFacilityLocations', Object.values(facilityMapping)); Object.keys(facilityMapping).map((facilityId: any) => { @@ -78,4 +247,5 @@ const actions: ActionTree = { this.dispatch('stock/updateStockItems', state.items); } } -export default actions; + +export default actions; \ No newline at end of file diff --git a/src/store/modules/stock/getters.ts b/src/store/modules/stock/getters.ts index 81c0c5b7..3abf4b23 100644 --- a/src/store/modules/stock/getters.ts +++ b/src/store/modules/stock/getters.ts @@ -6,5 +6,17 @@ const getters: GetterTree = { getStockItems(state) { return JSON.parse(JSON.stringify(state.items)); }, + getRestockItems(state) { + return JSON.parse(JSON.stringify(state.restockItems)) + }, + getScheduledInformation(state) { + return state.schedule + }, + getShopifyShops(state) { + return state.shopifyShops + }, + getScheduledJobs(state) { + return state.jobs + } }; export default getters; \ No newline at end of file diff --git a/src/store/modules/stock/index.ts b/src/store/modules/stock/index.ts index 60be7fe3..8fd65b1a 100644 --- a/src/store/modules/stock/index.ts +++ b/src/store/modules/stock/index.ts @@ -14,7 +14,17 @@ const orderModule: Module = { unidentifiedItems: [], initial: [] }, - fileName: "" + fileName: "", + restockItems: [], + schedule: { + scheduledTime: "", + shopId: "", + restockName: "", + productStoreId: "", + facilityId: "" + }, + shopifyShops: [], + jobs: {} }, actions, getters, diff --git a/src/store/modules/stock/mutation-types.ts b/src/store/modules/stock/mutation-types.ts index 91e0c1a6..2ec43ce2 100644 --- a/src/store/modules/stock/mutation-types.ts +++ b/src/store/modules/stock/mutation-types.ts @@ -1,2 +1,6 @@ export const SN_STOCK = 'stock' -export const STOCK_ITEMS_UPDATED = SN_STOCK + '/ITEMS_UPDATED' \ No newline at end of file +export const STOCK_ITEMS_UPDATED = SN_STOCK + '/ITEMS_UPDATED' +export const STOCK_SCHEDULE_ITEMS_UPDATED = SN_STOCK + '/SCHEDULE_ITEMS_UPDATED' +export const STOCK_SCHEDULED_INFORMATION = SN_STOCK + '/SCHEDULED_INFORMATION' +export const STOCK_SHOPIFY_SHOPS_UPDATED = SN_STOCK + '/SHOPIFY_SHOPS_UPDATED' +export const STOCK_JOBS_UPDATED = SN_STOCK + '/JOBS_UPDATED' diff --git a/src/store/modules/stock/mutations.ts b/src/store/modules/stock/mutations.ts index 7cf5fd83..bbadb1fd 100644 --- a/src/store/modules/stock/mutations.ts +++ b/src/store/modules/stock/mutations.ts @@ -8,6 +8,22 @@ const mutations: MutationTree = { state.items.original = payload.original; state.items.unidentifiedItems = payload.unidentifiedItems; state.items.initial = payload.initial; + }, + [types.STOCK_SCHEDULE_ITEMS_UPDATED] (state, payload) { + state.restockItems = payload; + }, + [types.STOCK_SCHEDULED_INFORMATION] (state, payload) { + state.schedule.scheduledTime = payload.scheduledTime; + state.schedule.shopId = payload.shopId; + state.schedule.restockName = payload.restockName; + state.schedule.productStoreId = payload.productStoreId + state.schedule.facilityId = payload.facilityId + }, + [types.STOCK_SHOPIFY_SHOPS_UPDATED] (state, payload) { + state.shopifyShops = payload + }, + [types.STOCK_JOBS_UPDATED] (state, payload) { + state.jobs = payload } } export default mutations; \ No newline at end of file diff --git a/src/store/modules/user/actions.ts b/src/store/modules/user/actions.ts index b86b12ea..fdc070f3 100644 --- a/src/store/modules/user/actions.ts +++ b/src/store/modules/user/actions.ts @@ -108,6 +108,8 @@ const actions: ActionTree = { resetConfig(); this.dispatch('order/updatePurchaseOrders', {parsed: {}, original: {}, unidentifiedItems: []}); this.dispatch('util/clearFacilities'); + this.dispatch('util/clearProductStores'); + this.dispatch('stock/clearScheduledStock') // clearing field mappings and current mapping when the user logout commit(types.USER_FIELD_MAPPINGS_UPDATED, {}) commit(types.USER_CURRENT_FIELD_MAPPING_UPDATED, {id: '', mappingType: '', name: '', value: {}}) diff --git a/src/store/modules/util/UtilState.ts b/src/store/modules/util/UtilState.ts index 859d779c..9622d4cf 100644 --- a/src/store/modules/util/UtilState.ts +++ b/src/store/modules/util/UtilState.ts @@ -3,4 +3,5 @@ export default interface UserState { facilityLocationsByFacilityId: any; goodIdentificationTypes: [], isProcessingFile: false, + productStores: [] } \ No newline at end of file diff --git a/src/store/modules/util/actions.ts b/src/store/modules/util/actions.ts index 259cad2e..453b2881 100644 --- a/src/store/modules/util/actions.ts +++ b/src/store/modules/util/actions.ts @@ -105,6 +105,33 @@ const actions: ActionTree = { } return state.facilities; }, + async fetchProductStores({ commit }) { + let productStores = []; + + const payload = { + "viewSize": 50, + "entityName": "ProductStore", + "fieldList": ["storeName", "productStoreId"], + "noConditionFind": "Y" + } + try { + const resp = await UtilService.fetchProductStores(payload); + if (!hasError(resp)) { + productStores = resp.data.docs; + } else { + throw resp.data; + } + } catch (err) { + logger.error(err) + } + + commit(types.UTIL_PRODUCT_STORES_UPDATED, productStores); + }, + + async clearProductStores({ commit }) { + commit(types.UTIL_PRODUCT_STORES_UPDATED, []); + }, + async updateFileProcessingStatus({ commit }, status){ commit(types.UTIL_FILE_PROCESSING_STATUS_UPDATED, { status }); }, diff --git a/src/store/modules/util/getters.ts b/src/store/modules/util/getters.ts index 47e6948d..d068f4af 100644 --- a/src/store/modules/util/getters.ts +++ b/src/store/modules/util/getters.ts @@ -14,6 +14,10 @@ const getters: GetterTree = { }, getFileProcessingStatus(state) { return state.isProcessingFile; + }, + getProductStores(state) { + return state.productStores; } + } export default getters; \ No newline at end of file diff --git a/src/store/modules/util/index.ts b/src/store/modules/util/index.ts index 3b3c25b5..4222bdca 100644 --- a/src/store/modules/util/index.ts +++ b/src/store/modules/util/index.ts @@ -11,7 +11,8 @@ const userModule: Module = { facilities: [], facilityLocationsByFacilityId: {}, goodIdentificationTypes: [], - isProcessingFile: false + isProcessingFile: false, + productStores: [] }, getters, actions, diff --git a/src/store/modules/util/mutation-types.ts b/src/store/modules/util/mutation-types.ts index 31c4f81a..136210c8 100644 --- a/src/store/modules/util/mutation-types.ts +++ b/src/store/modules/util/mutation-types.ts @@ -3,4 +3,4 @@ export const UTIL_FACILITIES_UPDATED = SN_UTIL + '/FACILITIES_UPDATED' export const UTIL_FACILITY_LOCATIONS_BY_FACILITY_ID = SN_UTIL + '/FACILITY_LOCATIONS_BY_FACILITY_ID' export const UTIL_GOOD_IDENTIFICATION_TYPES_UPDATED = SN_UTIL + '/GOOD_IDENTIFICATION_TYPES_UPDATED' export const UTIL_FILE_PROCESSING_STATUS_UPDATED = SN_UTIL + '/FILE_PROCESSING_STATUS_UPDATED' - +export const UTIL_PRODUCT_STORES_UPDATED = SN_UTIL + '/PRODUCT_STORES_UPDATED' diff --git a/src/store/modules/util/mutations.ts b/src/store/modules/util/mutations.ts index 9080fad7..13c93ea7 100644 --- a/src/store/modules/util/mutations.ts +++ b/src/store/modules/util/mutations.ts @@ -16,6 +16,9 @@ const mutations: MutationTree = { }, [types.UTIL_FILE_PROCESSING_STATUS_UPDATED] (state, payload) { state.isProcessingFile = payload.status; - } + }, + [types.UTIL_PRODUCT_STORES_UPDATED] (state, payload) { + state.productStores = payload; + } } export default mutations; \ No newline at end of file diff --git a/src/theme/variables.css b/src/theme/variables.css index bc8f0ef9..6df17b20 100644 --- a/src/theme/variables.css +++ b/src/theme/variables.css @@ -273,6 +273,23 @@ http://ionicframework.com/docs/theming/ */ text-align: center; } +.date-time-button::part(native) { + box-shadow: none; + border-radius: 8px; + padding-inline: 12px; + padding-top: 6px; + padding-bottom: 6px; + background: var(--ion-color-step-300, #edeef0); + color: var(--ion-text-color, #000); + font-family: inherit; +} + +.date-time-modal { + --width: 320px; + --height: 445px; + --border-radius: 8px; +} + @media (min-width: 991px) { .desktop-only { display: unset; @@ -281,4 +298,4 @@ http://ionicframework.com/docs/theming/ */ .mobile-only { display: none; } -} \ No newline at end of file +} diff --git a/src/views/SavedMappings.vue b/src/views/SavedMappings.vue index 71bf19e0..c322c6f0 100644 --- a/src/views/SavedMappings.vue +++ b/src/views/SavedMappings.vue @@ -25,6 +25,12 @@ {{ mapping.name }} + + {{ translate("Scheduled restock") }} + + {{ mapping.name }} + +