Creating the reservation services and updating Order Hub to use the new files
Procedure
Create a service to call the Create reservation API from Sterling Inventory Visibility to create reservation.
- Go to src-custom/app/features/create-reservation and create a folder called services.
- Create a service at src-custom/app/features/create-reservation/services.
-
Run the following command:
ng g s create-reservation
This will create a new service under the services folder. This service can be used to add API calls.
-
Copy following content into the create-reservation.service.ts file:
import { Injectable } from '@angular/core'; import { BucCommBEHttpWrapperService } from '@buc/svc-angular'; import { Observable, throwError } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class CreateReservationService { private resourceDomain: string = 'inventory'; private options: any; private domain: any; public reservationRef: any; public itemData: any constructor(private http: BucCommBEHttpWrapperService) { this.domain = BucCommBEHttpWrapperService.getPathPrefix(this.resourceDomain); this.options = BucCommBEHttpWrapperService.getRequestOptions(this.resourceDomain); } createReservation(tenantId, input): Observable<any> { if (tenantId === undefined || tenantId === null || tenantId === '') { return throwError(new Error('Missing required parameter: tenantId')); } let path = '/{tenant}/v1/reservations'; path = path.replace('{tenant}', tenantId); const url = this.domain + path; const obsToReturn$ = this.http.post(url, this.resourceDomain, null, input, this.options); return obsToReturn$; } getReservation(tenantId, referenceId): Observable<any> { if (tenantId === undefined || tenantId === null || tenantId === '') { return throwError(new Error('Missing required parameter: tenantId')); } let path = '/{tenant}/v1/reservations?reference={referenceId}'; path = path.replace('{tenant}', tenantId).replace('{referenceId}', referenceId); const url = this.domain + path; const obsToReturn$ = this.http.get(url, this.resourceDomain, null, this.options); return obsToReturn$; } }
Create a reservation action service.
- Create another service in the same services folder.
-
Run the following command:
ng g s reservation-action
This will create a new service under the services folder. This service can be used to add all the overflow menu actions.
-
Copy the following content into the reservation-action.service.ts
file:
import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { BucNotificationService, ActionProcessorService } from '@buc/common-components'; import { TranslateService } from '@ngx-translate/core'; import { CustomConstants } from '../custom-constants'; import { map } from 'rxjs/operators'; import { ActionParams } from '@buc/inventory-shared/lib/actions/paramtypes'; import { CreateReservationService } from './create-reservation.service'; @Injectable({ providedIn: 'root' }) export class ReservationActionService { constructor( public actionSvc: ActionProcessorService, public translate: TranslateService, public bucNotificationService: BucNotificationService, public router: Router, public createReservationSvc: CreateReservationService) { actionSvc.select<ActionParams>(CustomConstants.ACTION_IDS_CREATE_RESERVATION).pipe( map(res => { this.executeActionDetails(res.params); }) ).subscribe(); } async executeActionDetails(params: ActionParams) { this.createReservationSvc.itemData = params.data?.item; } }
Add the reservation action service to the Order Hub code:
- Open the src-custom/app/app-customization.impl.ts file for editing.
-
Update the imports array to include modules to add the reservation-action service:
BucActionsModule.forChild( [ { name: CustomConstants.ACTION_IDS_CREATE_RESERVATION, action: ReservationActionService } ] )
-
As a result, the imports array should have the following code:
static readonly imports = [ RouterModule.forChild(customRoutes), BucCommonComponentsModule, BucFeatureComponentsModule, BucIconsModule, SharedModule, BucActionsModule.forChild( [ { name: CustomConstants.ACTION_IDS_CREATE_RESERVATION, action: ReservationActionService } ] ) ];
-
Update the import with the following code:
import { CustomConstants } from './features/create-reservation/custom-constants'; import { ReservationActionService } from './features/create-reservation/services/reservation-action.service'; import { BucActionsModule } from '@buc/common-components';
Add a new action for the create reservation:
- Open the src-custom/app/features/search/inventory-table/inventory-table.component.ts file for editing.
-
Add the following import:
import { CustomConstants } from '../../create-reservation/custom-constants';
-
Add the following method at the end:
private _setCreateReservation(itemData) { this.actionService.dispatch<ActionParams>( CustomConstants.ACTION_IDS_CREATE_RESERVATION, { searchCriteria: this.searchCriteria, data: itemData, pageNumber: 1, initialLoad: true, dataMap: [itemData], ctxSvc: this.ctxSvc, } ); }
-
In the
onOverflowMenuClick
method, add the following constant in the items array:CustomConstants.ACTION_CREATE_RESERVATION
-
As a result, the
onOverflowMenuClick
method should resemble the following code:onOverflowMenuClick(item: any) { this.itemData = item.key; this.overflowMenuId = item.key.itemDescriptiveKey; const items = [ Constants.ACTION_SET_SAFETY_STOCKS, Constants.ACTION_SET_FULFILLMENT_OPTIONS, Constants.ACTION_TRANSFER_INVENTORY, Constants.ACTION_ADJUST_INVENTORY, CustomConstants.ACTION_CREATE_RESERVATION ]; if (item.key.type.bundle) { this.removeOverflowMenuActions(items); } else { this._setOverflowMenu(item.key.type.modelItem); } }
-
In the
onOverflowMenuActionSelected
method, add a new case:case CustomConstants.ACTION_CREATE_RESERVATION: this._setCreateReservation({ item: this.itemData }); break;
-
As a result, the
onOverflowMenuActionSelected
method should resemble the following code:protected onOverflowMenuActionSelected(id: string) { switch (id) { case Constants.ACTION_IDS_VIEW_DETAILS: this._details({ item: this.itemData }); break; case Constants.ACTION_SET_SAFETY_STOCKS: this._setSafetyStockMultiple(); break; case Constants.ACTION_SET_FULFILLMENT_OPTIONS: this._setFulfillmentOptionsMultiple(); break; case Constants.ACTION_TRANSFER_INVENTORY: this._moveInventory({ data: { itemData: this.itemData } }); break; case Constants.ACTION_ADJUST_INVENTORY: this._setAdjustInventoryMultiple(); break; case CustomConstants.ACTION_CREATE_RESERVATION: this._setCreateReservation({ item: this.itemData }); break; } }
-
In the
_setOverflowMenu
method, add new action ID in theactionIds
array:CustomConstants.ACTION_CREATE_RESERVATION
-
As a result, the
_setOverflowMenu
method should resemble the following code:private _setOverflowMenu(modelItemSelected = false) { this.getActionResourceIds(); let actionIds = []; if (this.searchCriteria.filterCriteria.locationType !== Constants.VALUE_CONSIDERALLNODES) { actionIds = [ Constants.ACTION_IDS_VIEW_DETAILS, Constants.ACTION_SET_SAFETY_STOCKS, Constants.ACTION_SET_FULFILLMENT_OPTIONS, Constants.ACTION_TRANSFER_INVENTORY, CustomConstants.ACTION_CREATE_RESERVATION ]; if (!modelItemSelected) { actionIds.splice(1, 0, Constants.ACTION_ADJUST_INVENTORY); } if (this.isSafetyStockRuleEnabled) { const index = actionIds.indexOf(Constants.ACTION_SET_SAFETY_STOCKS); if (index !== -1) { actionIds.splice(index, 1); } } } else { actionIds = [Constants.ACTION_IDS_VIEW_DETAILS]; } const tableConfiguration = this.getTableConfiguration(); tableConfiguration.setActiveOverflowMenuActions(actionIds); this.setOverflowMenuResourceIds(this.actionResourceIds, actionIds); this.overflowMenu = tableConfiguration.getOverflowMenuActions(); }
- Go to src-custom/app/features/create-reservation and create a folder called components.
-
Create the following files inside the components folder:
- create-reservation-form.component.ts
- create-reservation-form.component.html
- create-reservation-form.component.scss
- create-reservation-form.module.ts
- Open your form in the IBM Carbon UI Builder and click Export. Ensure that the Angular tab is selected.
-
Copy the contents of
src/app/components/create-reservation-form/create-reservation-form.component.ts
from the IBM Carbon UI Builder code into the newly created
create-reservation-form.component.ts file.
- Open the newly created create-reservation-form.component.html file for editing.
-
Add the following code:
<form [formGroup]="createReservationForm"> </form>
-
After the first line of the newly added code, copy the contents of
src/app/components/create-reservation-form/create-reservation-form.component.html
from the IBM Carbon UI Builder code into the file.
Since the reactive forms module is used, a
formGroup
is required for form submission andformControlName
is required for each field.Therefore:- Add the following
formControlName
for each field:formControlName = reference
forreference
input fields.After adding theformControlName
it should resemble the following snippet:<input ibmText name="reference" formControlName="reference" placeholder="" />
- Similarly, a
formControlName
is required for each and every field in the form.Replace all the
(event)
parameters in the file with($event)
.Doing so resolves the following errors:
Property 'value' does not exist on type EventTarget in TypeScript
. - Change the
(selected)
event of the shipping node and distribution group as follows in each of theiribm-dropdown
snippets:In the shipping node drop down, denoted by theibm-dropdown
snippet withformControlName="shippingNode"
, change the(selected)
event to:(selected)="onSelectShippingNode($event)"
In the distribution group drop down, denoted by theibm-dropdown
snippet withformControlName="dg"
, change the(selected)
event to:(selected)="onSelectDistributionGroup($event)"
These methods are required to capture events when either of the shipping node or distribution group drop down is selected.
For example:
After adding all the control values, the create-reservation-form.component.html file resembles the following code:<form [formGroup]="createReservationForm"> <ibm-accordion [align]="accordion165433494446278754849833236715917Align"> <ibm-accordion-item [title]="accordionItem36327672493936585592059716298563Title" (selected)="accordionItem36327672493936585592059716298563Selected.emit($event)" > <div ibmGrid> <div ibmRow> <div ibmCol> <ibm-label helperText=""> Reference <input ibmText name="reference" formControlName="reference" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-label helperText=""> Segment type <input ibmText name="segmentType"formControlName="segmentType" placeholder="" /> </ibm-label> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <ibm-label helperText=""> Time to expire <input ibmText name="timeToExpire" formControlName="timeToExpire" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-dropdown [label]="demandTypeLabel" [helperText]="demandTypeHelperText" [placeholder]="demandTypePlaceholder" [theme]="demandTypeTheme" [invalid]="demandTypeInvalid" [invalidText]="demandTypeInvalidText" [size]="demandTypeSize" [warn]="demandTypeWarn" [warnText]="demandTypeWarnText" [disabled]="demandTypeDisabled" [dropUp]="demandTypeDropUp" [selectionFeedback]="demandTypeSelectionFeedback" [type]="demandTypeType" (selected)="demandTypeSelected.emit($event)" (close)="demandTypeClose.emit($event)" formControlName="demandType" > <ibm-dropdown-list [items]="demandTypeItems"></ibm-dropdown-list> </ibm-dropdown> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <ibm-label helperText=""> Segment <input ibmText name="segment" formControlName="segment" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-checkbox name="considerSafetyStock" id="considerSafetyStock" [(checked)]="considerSafetyStockChecked" (checkedChange)="considerSafetyStockCheckedChange.emit($event)" class="checkbox-margin" formControlName="considerSafetyStock" > Consider safety stock </ibm-checkbox> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <ibm-label helperText=""> Line Id <input ibmText name="lineId" formControlName="lineId" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-label helperText=""> Item Id <input ibmText name="itemId" formControlName="itemId" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-label helperText=""> Unit of measure <input ibmText name="unitOfMeasure" formControlName="unitOfMeasure" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-label helperText=""> Product class <input ibmText name="productClass" formControlName="productClass" placeholder="" /> </ibm-label> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <ibm-label helperText=""> Delivery method <input ibmText name="deliveryMethod" formControlName="deliveryMethod" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-number [helperText]="quantityHelperText" name="quantity" [value]="quantityValue" (change)="quantityValueChange.emit($event.value)" [label]="quantityLabel" [theme]="quantityTheme" [min]="quantityMin" [max]="quantityMax" [step]="quantityStep" [invalid]="quantityInvalid" [invalidText]="quantityInvalidText" [warn]="quantityWarn" [warnText]="quantityWarnText" [size]="quantitySize" [disabled]="quantityDisabled" formControlName="quantity" > </ibm-number> </div> <div ibmCol> <ibm-label helperText=""> Segment <input ibmText name="lineSegment" formControlName="lineSegment" placeholder="" /> </ibm-label> </div> <div ibmCol> <ibm-label helperText=""> Segment Type <input ibmText name="lineSegmentType" formControlName="lineSegmentType" placeholder="" /> </ibm-label> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <ibm-dropdown [label]="shippingNodeLabel" [helperText]="shippingNodeHelperText" [placeholder]="shippingNodePlaceholder" [theme]="shippingNodeTheme" [invalid]="shippingNodeInvalid" [invalidText]="shippingNodeInvalidText" [size]="shippingNodeSize" [warn]="shippingNodeWarn" [warnText]="shippingNodeWarnText" [disabled]="shippingNodeDisabled" [dropUp]="shippingNodeDropUp" [selectionFeedback]="shippingNodeSelectionFeedback" [type]="shippingNodeType" (selected)="onSelectShippingNode($event)" (close)="shippingNodeClose.emit($event)" formControlName="shippingNode" > <ibm-dropdown-list [items]="shippingNodeItems"></ibm-dropdown-list> </ibm-dropdown> </div> <div ibmCol> <ibm-dropdown [label]="dgLabel" [helperText]="dgHelperText" [placeholder]="dgPlaceholder" [theme]="dgTheme" [invalid]="dgInvalid" [invalidText]="dgInvalidText" [size]="dgSize" [warn]="dgWarn" [warnText]="dgWarnText" [disabled]="dgDisabled" [dropUp]="dgDropUp" [selectionFeedback]="dgSelectionFeedback" [type]="dgType" (selected)="onSelectDistributionGroup($event)" (close)="dgClose.emit($event)" formControlName="dg" > <ibm-dropdown-list [items]="dgItems"></ibm-dropdown-list> </ibm-dropdown> </div> </div> <div ibmRow class="margin-top"> <div ibmCol> <button ibmButton="secondary" (click)="button3886839157349837322918347909375902Clicked.emit()" > Cancel </button> <button ibmButton="primary" (click)="onSave()" class="create-btn-margin" > Create </button> </div> </div> </div> </ibm-accordion-item> </ibm-accordion> </form>
Accordion values and button values will be different than the design that is developed. While copying the preceding code:- Add accordion [align] and [title] properties as per the remarks in the code while exporting the fragment.
- Ensure that the Create and Delete button (click) property is the same as the fragment design.
- Add the following
-
Copy the contents of
src/app/components/create-reservation-form/create-reservation-form.module.ts
from the IBM Carbon UI Builder code into the newly created
create-reservation-form.module.ts file.
Other than the above module, a few angular modules are also needed:
FormsModule
andReactiveFormsModule
.The file should contain the following code:import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AccordionModule, GridModule, InputModule, DropdownModule, CheckboxModule, NumberModule, ComboBoxModule, ButtonModule } from 'carbon-components-angular'; import { CreateReservationForm } from './create-reservation-form.component'; @NgModule({ imports: [ AccordionModule, GridModule, InputModule, DropdownModule, CheckboxModule, NumberModule, ComboBoxModule, ButtonModule, FormsModule, ReactiveFormsModule ], declarations: [CreateReservationForm], exports: [CreateReservationForm] }) export class CreateReservationFormModule { }
-
Copy the contents of
src/app/components/create-reservation-form/create-reservation-form.component.scss
from the IBM Carbon UI Builder code into the newly created
create-reservation-form.component.scss file.
-
Open the newly created create-reservation-form.component.ts file for
editing.
- Change the selector name to
'buc-create-reservation-form'
.@Component({ selector: "buc-create-reservation-form", templateUrl: "./create-reservation-form.component.html", styleUrls: ["./create-reservation-form.component.scss"] })
-
Implement the
OnInit
interface in this component. Addimplements OnInit
after the class name.@Component({ selector: "buc-create-reservation-form", templateUrl: "./create-reservation-form.component.html", styleUrls: ["./create-reservation-form.component.scss"] }) export class CreateReservationForm implements OnInit{
Then, some of the fields will need to be updated so that they can be used:
- Change
@Input() quantityValue = 50;
to@Input() quantityValue = 1;
- Add new variables and methods by adding new variables after all the variable
declarations:
// new variables public validDemandTypes; orgCode: string; dgMap: any = {}; public tenantId; public isCancelled: boolean; createReservationForm: FormGroup; private nlsMap: any = { 'custom.LABEL_CREATE_RESERVATION': '', 'custom.LABEL_RESERVATION_EXPIRY': '', 'custom.ERROR_INVALID_EXPIRY': '', 'custom.ERROR_RESERVATION': '', 'custom.SUCCESS_RESERVATION': '' }; constructor( private locCommonSvc: LocalCommonService, public demandService: InventoryDemandService, private inventoryShipNodesService: InventoryShipNodesService, private dgSvc: InventoryDistributionService, private reservationService: CreateReservationService, private bucNotificationService: BucNotificationService, private router: Router, private translateSvc: TranslateService ) {} ngOnInit(): void { this.createReservationForm = new FormGroup({ reference: new FormControl(), timeToExpire: new FormControl(), demandType: new FormControl([]), segment: new FormControl(), segmentType: new FormControl(), considerSafetyStock: new FormControl(), lineId: new FormControl(), itemId: new FormControl(), unitOfMeasure: new FormControl(), productClass: new FormControl(), deliveryMethod: new FormControl(), quantity: new FormControl(), lineSegment: new FormControl(), lineSegmentType: new FormControl(), shippingNode: new FormControl(), dg: new FormControl() }); this.initialize(); this.tenantId = BucSvcAngularStaticAppInfoFacadeUtil.getInventoryTenantId(); this._initTranslations(); } /** Fetch translations for the page */ private async _initTranslations() { const keys = Object.keys(this.nlsMap); const json = await this.translateSvc.get(keys).toPromise(); keys.forEach(k => this.nlsMap[k] = json[k]); } async initialize(clearForm = false) { await this.loadDemandTypes(); await this.getShipNodes(); await this.loadDG(); } // loading demand types async loadDemandTypes() { try { this.validDemandTypes = await getValidDemandTypes(this.demandService); const data = this.validDemandTypes.map(sup => ({ content: sup, selected: false, id: sup })); this.mapDemandTypes(); } catch (e) { this.locCommonSvc.showErrorNotification('error', e.message); } } mapDemandTypes() { this.demandTypeItems = this.validDemandTypes.map(item => { return { content: item }; }); } // loading ship nodes private async getShipNodes() { if (!this.shippingNodeItems || this.shippingNodeItems.length === 0) { const response = await this.inventoryShipNodesService.getIVShipNodesByTenantID().toPromise(); let shippingNodes = []; if (response && response.length) { shippingNodes = response.map(item => item.shipNode); this.shippingNodeItems = shippingNodes.map(item => { return { content: item }; }); } } } // loading DG async loadDG() { try { const resp = await this.dgSvc.getDistributionRuleListByPage(this.orgCode, 1, 999, '').toPromise(); const list = resp.distributionGroups .filter(dg => (!dg.dgType || dg.dgType === 'PROD') && (!dg.dgPurpose || dg.dgPurpose === 'SOURCING')) .map(dg => { const id = dg.dgId || dg.dgKey; this.dgMap[id] = dg; return { id, content: dg.dgName, selected: false, value: id }; }) .sort((a, b) => a.content.toLocaleLowerCase().localeCompare(b.content.toLocaleLowerCase())); this.dgItems = list; } catch (e) { this.locCommonSvc.showErrorNotification('error', e.message); } } async onSave() { let shipNodeValue = ''; if (this.createReservationForm.value.shippingNode && this.createReservationForm.value.shippingNode.length) { shipNodeValue = this.createReservationForm.value.shippingNode.find(st => st.selected).content; } let dgValue = ''; if (this.createReservationForm.value.dg && this.createReservationForm.value.dg.length) { dgValue = this.createReservationForm.value.dg.find(st => st.selected).content; } let demandTypeValue = ''; if (this.createReservationForm.value.dg && this.createReservationForm.value.demandType.length) { demandTypeValue = this.createReservationForm.value.demandType.content; } const request = { reference: this.createReservationForm.value.reference, timeToExpire: this.createReservationForm.value.timeToExpire, segment: this.createReservationForm.value.segment, segmentType: this.createReservationForm.value.segmentType, demandType: this.createReservationForm.value.demandType.content, considerSafetyStock: this.createReservationForm.value.considerSafetyStock ? this.createReservationForm.value.considerSafetyStock : false, lines: [{ lineId: this.createReservationForm.value.lineId, itemId: this.createReservationForm.value.itemId, unitOfMeasure: this.createReservationForm.value.unitOfMeasure, productClass: this.createReservationForm.value.productClass, deliveryMethod: this.createReservationForm.value.deliveryMethod, shipNode: shipNodeValue, distributionGroup: dgValue, segment: this.createReservationForm.value.lineSegment, segmentType: this.createReservationForm.value.lineSegmentType, quantity: this.createReservationForm.value.quantity }] }; // Call reservation API here try { await this.reservationService.createReservation(this.tenantId, request).toPromise(); this.showNotification('success', this.nlsMap['custom.SUCCESS_RESERVATION']); } catch (error) { this.showNotification('error', this.nlsMap['custom.ERROR_RESERVATION'] + ' ' + error.error_message); } } // notification showNotification(statusType, message) { const notification = new BucNotificationModel({ statusType, statusContent: message }); this.bucNotificationService.send([notification]); } onCancel() { this.isCancelled = true; this.router.navigate([Constants.RESULTS_ROUTE]); }
- Update the import section with the following
lines:
import { Component, Input, Output, EventEmitter, OnInit } from "@angular/core"; import { FormControl, FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { BucNotificationModel, BucNotificationService } from "@buc/common-components"; import { InventoryDemandService, InventoryDistributionService, CommonService as LocalCommonService, getValidDemandTypes, Constants , InventoryShipNodesService} from "@buc/inventory-shared"; import { TranslateService } from "@ngx-translate/core"; import { BucSvcAngularStaticAppInfoFacadeUtil } from '@buc/svc-angular'; import { CreateReservationService } from "../services/create-reservation.service";
- As a result, the create-reservation-form.component.ts file should resemble
the following
file:
import { Component, Input, Output, EventEmitter, OnInit } from "@angular/core"; import { FormControl, FormGroup } from "@angular/forms"; import { ActivatedRoute, Router } from "@angular/router"; import { BucNotificationModel, BucNotificationService } from "@buc/common-components"; import { InventoryDemandService, InventoryDistributionService, CommonService as LocalCommonService, getValidDemandTypes, Constants , InventoryShipNodesService} from "@buc/inventory-shared"; import { TranslateService } from "@ngx-translate/core"; import { BucSvcAngularStaticAppInfoFacadeUtil } from '@buc/svc-angular'; import { CreateReservationService } from "../services/create-reservation.service"; @Component({ selector: "buc-create-reservation-form", templateUrl: "./create-reservation-form.component.html", styleUrls: ["./create-reservation-form.component.scss"] }) export class CreateReservationForm implements OnInit{ @Input() accordion165433494446278754849833236715917Align = "end"; @Input() accordionItem36327672493936585592059716298563Title = "Create reservation"; @Input() demandTypeLabel = "Demand type"; @Input() demandTypeHelperText = ""; @Input() demandTypePlaceholder = ""; @Input() demandTypeTheme = "dark"; @Input() demandTypeInvalid = false; @Input() demandTypeInvalidText = ""; @Input() demandTypeSize = "md"; @Input() demandTypeWarn = false; @Input() demandTypeWarnText = ""; @Input() demandTypeDisabled = false; @Input() demandTypeDropUp = false; @Input() demandTypeSelectionFeedback = "top-after-reopen"; @Input() demandTypeType: "single" | "multi" = "single"; @Input() demandTypeItems = []; @Input() considerSafetyStockChecked = false; @Input() quantityHelperText = ""; @Input() quantityValue = 1; @Input() quantityLabel = "Quantity"; @Input() quantityTheme = ""; @Input() quantityMin = 0; @Input() quantityMax = 100; @Input() quantityStep = 1; @Input() quantityInvalid = false; @Input() quantityInvalidText = undefined; @Input() quantityWarn = undefined; @Input() quantityWarnText = undefined; @Input() quantitySize = "md"; @Input() quantityDisabled = undefined; @Input() shippingNodeLabel = "Shipping node"; @Input() shippingNodeHelperText = ""; @Input() shippingNodePlaceholder = ""; @Input() shippingNodeTheme = "dark"; @Input() shippingNodeInvalid = false; @Input() shippingNodeInvalidText = ""; @Input() shippingNodeSize = "md"; @Input() shippingNodeWarn = false; @Input() shippingNodeWarnText = ""; @Input() shippingNodeDisabled = false; @Input() shippingNodeDropUp = false; @Input() shippingNodeSelectionFeedback = "top-after-reopen"; @Input() shippingNodeType: "single" | "multi" = "single"; @Input() shippingNodeItems = []; @Input() dgLabel = "Distribution group"; @Input() dgHelperText = ""; @Input() dgPlaceholder = ""; @Input() dgTheme = "dark"; @Input() dgInvalid = false; @Input() dgInvalidText = ""; @Input() dgSize = "md"; @Input() dgWarn = false; @Input() dgWarnText = ""; @Input() dgDisabled = false; @Input() dgDropUp = false; @Input() dgSelectionFeedback = "top-after-reopen"; @Input() dgType: "single" | "multi" = "single"; @Input() dgItems = []; @Output() accordionItem36327672493936585592059716298563Selected = new EventEmitter(); @Output() demandTypeSelected = new EventEmitter<any>(); @Output() demandTypeClose = new EventEmitter<any>(); @Output() considerSafetyStockCheckedChange = new EventEmitter<boolean>(); @Output() quantityValueChange = new EventEmitter<number>(); @Output() quantityChange = new EventEmitter<any>(); @Output() shippingNodeSelected = new EventEmitter<any>(); @Output() shippingNodeClose = new EventEmitter<any>(); @Output() dgSelected = new EventEmitter<any>(); @Output() dgClose = new EventEmitter<any>(); @Output() button3886839157349837322918347909375902Clicked = new EventEmitter(); @Output() creatClicked = new EventEmitter(); // new variables public validDemandTypes; orgCode: string; dgMap: any = {}; public tenantId; public isCancelled: boolean; createReservationForm: FormGroup; private nlsMap: any = { 'custom.LABEL_CREATE_RESERVATION': '', 'custom.LABEL_RESERVATION_EXPIRY': '', 'custom.ERROR_INVALID_EXPIRY': '', 'custom.ERROR_RESERVATION': '', 'custom.SUCCESS_RESERVATION': '' }; constructor( private locCommonSvc: LocalCommonService, public demandService: InventoryDemandService, private inventoryShipNodesService: InventoryShipNodesService, private dgSvc: InventoryDistributionService, private reservationService: CreateReservationService, private bucNotificationService: BucNotificationService, private router: Router, private translateSvc: TranslateService, private route: ActivatedRoute ) {} ngOnInit(): void { this.createReservationForm = new FormGroup({ reference: new FormControl(), timeToExpire: new FormControl(), demandType: new FormControl([]), segment: new FormControl(), segmentType: new FormControl(), considerSafetyStock: new FormControl(), lineId: new FormControl(), itemId: new FormControl(), unitOfMeasure: new FormControl(), productClass: new FormControl(), deliveryMethod: new FormControl(), quantity: new FormControl(), lineSegment: new FormControl(), lineSegmentType: new FormControl(), shippingNode: new FormControl(), dg: new FormControl() }); this.initialize(); this.tenantId = BucSvcAngularStaticAppInfoFacadeUtil.getInventoryTenantId(); this._initTranslations(); } /** Fetch translations for the page */ private async _initTranslations() { const keys = Object.keys(this.nlsMap); const json = await this.translateSvc.get(keys).toPromise(); keys.forEach(k => this.nlsMap[k] = json[k]); } async initialize(clearForm = false) { await this.loadDemandTypes(); await this.getShipNodes(); await this.loadDG(); // set default values in the form this.createReservationForm.controls['itemId'].setValue(this.reservationService.itemData?.itemId); this.createReservationForm.controls['productClass'].setValue(this.reservationService.itemData?.productClass); this.createReservationForm.controls['unitOfMeasure'].setValue(this.reservationService.itemData?.unitOfMeasure); } // loading demand types async loadDemandTypes() { try { this.validDemandTypes = await getValidDemandTypes(this.demandService); const data = this.validDemandTypes.map(sup => ({ content: sup, selected: false, id: sup })); this.mapDemandTypes(); } catch (e) { this.locCommonSvc.showErrorNotification('error', e.message); } } mapDemandTypes() { this.demandTypeItems = this.validDemandTypes.map(item => { return { content: item }; }); } // loading ship nodes private async getShipNodes() { if (!this.shippingNodeItems || this.shippingNodeItems.length === 0) { const response = await this.inventoryShipNodesService.getIVShipNodesByTenantID().toPromise(); let shippingNodes = []; if (response && response.length) { shippingNodes = response.map(item => item.shipNode); this.shippingNodeItems = shippingNodes.map(item => { return { content: item }; }); } } } // loading DG async loadDG() { try { const resp = await this.dgSvc.getDistributionRuleListByPage(this.orgCode, 1, 999, '').toPromise(); const list = resp.distributionGroups .filter(dg => (!dg.dgType || dg.dgType === 'PROD') && (!dg.dgPurpose || dg.dgPurpose === 'SOURCING')) .map(dg => { const id = dg.dgId || dg.dgKey; this.dgMap[id] = dg; return { id, content: dg.dgName, selected: false, value: id }; }) .sort((a, b) => a.content.toLocaleLowerCase().localeCompare(b.content.toLocaleLowerCase())); this.dgItems = list; } catch (e) { this.locCommonSvc.showErrorNotification('error', e.message); } } async onSave() { const request = { reference: this.createReservationForm.value.reference, timeToExpire: this.createReservationForm.value.timeToExpire, segment: this.createReservationForm.value.segment, segmentType: this.createReservationForm.value.segmentType, demandType: this.createReservationForm.value.demandType.content, considerSafetyStock: this.createReservationForm.value.considerSafetyStock ? this.createReservationForm.value.considerSafetyStock : false, lines: [{ lineId: this.createReservationForm.value.lineId, itemId: this.createReservationForm.value.itemId, unitOfMeasure: this.createReservationForm.value.unitOfMeasure, productClass: this.createReservationForm.value.productClass, deliveryMethod: this.createReservationForm.value.deliveryMethod, shipNode: this.createReservationForm.value.shippingNode?this.createReservationForm.value.shippingNode.content:'', distributionGroup: this.createReservationForm.value.dg?this.createReservationForm.value.dg.content:'', segment: this.createReservationForm.value.lineSegment, segmentType: this.createReservationForm.value.lineSegmentType, quantity: this.createReservationForm.value.quantity }] }; // Call reservation API here try { await this.reservationService.createReservation(this.tenantId, request).toPromise(); this.showNotification('success', this.nlsMap['custom.SUCCESS_RESERVATION']); // enabling dg and shipping node this.dgDisabled = false; this.shippingNodeDisabled = false; // After successful reservation storing reference id to populate data in table this.reservationService.reservationRef = this.createReservationForm.value.reference; } catch (error) { console.log("error", error) this.showNotification('error', this.nlsMap['custom.ERROR_RESERVATION'] + ' ' + error.error.error_message); } } // notification showNotification(statusType, message) { const notification = new BucNotificationModel({ statusType, statusContent: message }); this.bucNotificationService.send([notification]); } onCancel() { this.isCancelled = true; this.router.navigate([Constants.RESULTS_ROUTE]); } onSelectShippingNode(event) { // Disabling dg once shipping node is selected this.dgDisabled = true; } onSelectDistributionGroup(event){ // Disabling shipping node once dg is selected this.shippingNodeDisabled = true; } }
- Change the selector name to
-
Open the src-custom/app/app-customization.impl.ts file for
editing.
- Add
CreateResevationFormModule
into the imports array. - Update the corresponding
import.
import { CreateReservationFormModule } from './features/create-reservation/components/create-reservation-form.module';
- As a result, the src-custom/app/app-customization.impl.ts file should
resemble the following file:
import { RouterModule, Routes } from '@angular/router'; import { Constants, InventoryModuleUrlGuardService } from '@buc/inventory-shared'; import { BucCommonClassesConnectorResourcePermissionsGuard } from '@buc/svc-angular'; import { CreateReservationComponent } from './features/create-reservation/create-reservation.component'; import { BucActionsModule, BucCommonComponentsModule, BucFeatureComponentsModule, BucIconsModule } from '@buc/common-components'; import { SharedModule } from '@buc/inventory-shared'; import { CreateReservationFormModule } from './features/create-reservation/components/create-reservation-form.module'; import { CustomConstants } from './features/create-reservation/custom-constants'; import { ReservationActionService } from './features/create-reservation/services/reservation-action.service'; export const customRoutes: Routes = [ { canActivate: [InventoryModuleUrlGuardService], path: 'create-reservation', component: CreateReservationComponent, data: { id: 'CUSINV0001' // New resourceId to control permissions } } ]; export class AppCustomizationImpl { static readonly components = [CreateReservationComponent]; static readonly providers = []; static readonly imports = [ RouterModule.forChild(customRoutes), BucCommonComponentsModule, BucFeatureComponentsModule, BucIconsModule, SharedModule, CreateReservationFormModule, BucActionsModule.forChild( [ { name: CustomConstants.ACTION_IDS_CREATE_RESERVATION, action: ReservationActionService } ] ) ]; static readonly exports = [RouterModule]; }
- Add
-
Add the following code to the
src-custom/app/features/create-reservation/create-reservation.component.html file after the
<!–Reservation form -->
comment:<buc-create-reservation-form></buc-create-reservation-form>
-
Go back to Order Hub and reload the frame. The form should be visible on the UI: