shipping and payment updates
This commit is contained in:
parent
5185cb375d
commit
d1bc0eb45a
@ -36,33 +36,11 @@
|
||||
</app-travel-plan>
|
||||
</mat-step>
|
||||
|
||||
<!-- Insurance Step -->
|
||||
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||
[completed]="stepsCompleted.insurance" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Insurance</ng-template>
|
||||
<app-insurance (completed)="onInsuranceSaved($event)" [headerid]="headerid">
|
||||
</app-insurance>
|
||||
</mat-step>
|
||||
|
||||
<!-- Shipping Step -->
|
||||
<!-- Shipping & Payment Step -->
|
||||
<mat-step [completed]="stepsCompleted.shipping" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Shipping</ng-template>
|
||||
<ng-template matStepLabel>Shipping & Payment</ng-template>
|
||||
<app-shipping (completed)="onShippingSaved($event)" [headerid]="headerid">
|
||||
</app-shipping>
|
||||
</mat-step>
|
||||
|
||||
<!-- Delivery Method Step -->
|
||||
<mat-step [completed]="stepsCompleted.deliveryMethod" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Delivery Method</ng-template>
|
||||
<app-delivery (completed)="onDeliveryMethodSaved($event)" [headerid]="headerid">
|
||||
</app-delivery>
|
||||
</mat-step>
|
||||
|
||||
<!-- Payment Step -->
|
||||
<mat-step [completed]="stepsCompleted.payment" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Payment</ng-template>
|
||||
<app-payment (completed)="onPaymentSaved($event)" [headerid]="headerid">
|
||||
</app-payment>
|
||||
</mat-step>
|
||||
</mat-stepper>
|
||||
</div>
|
||||
@ -7,18 +7,15 @@ import { ApplicationComponent } from "../application/application.component";
|
||||
import { HolderComponent } from '../holder/holder.component';
|
||||
import { GoodsComponent } from '../goods/goods.component';
|
||||
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
||||
import { InsuranceComponent } from '../insurance/insurance.component';
|
||||
import { PaymentComponent } from '../payment/payment.component';
|
||||
import { ShippingComponent } from '../shipping/shipping.component';
|
||||
import { DeliveryComponent } from '../delivery/delivery.component';
|
||||
import { UserPreferencesService } from '../../core/services/user-preference.service';
|
||||
import { UserPreferences } from '../../core/models/user-preference';
|
||||
|
||||
@Component({
|
||||
selector: 'app-add-carnet',
|
||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent,
|
||||
ShippingComponent, DeliveryComponent, PaymentComponent],
|
||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent,
|
||||
ShippingComponent],
|
||||
templateUrl: './add-carnet.component.html',
|
||||
styleUrl: './add-carnet.component.scss'
|
||||
})
|
||||
@ -36,10 +33,7 @@ export class AddCarnetComponent {
|
||||
holderSelection: false,
|
||||
goodsSection: false,
|
||||
travelPlan: false,
|
||||
insurance: false,
|
||||
shipping: false,
|
||||
deliveryMethod: false,
|
||||
payment: false
|
||||
shipping: false
|
||||
};
|
||||
|
||||
constructor(userPrefenceService: UserPreferencesService) {
|
||||
@ -51,7 +45,7 @@ export class AddCarnetComponent {
|
||||
}
|
||||
|
||||
onApplicationDetailCreated(headerid: number): void {
|
||||
this.headerid = this.headerid;
|
||||
this.headerid = headerid;
|
||||
this.stepsCompleted.applicationDetail = true;
|
||||
this.isLinear = false; // Disable linear mode after application detail is created
|
||||
}
|
||||
@ -68,19 +62,7 @@ export class AddCarnetComponent {
|
||||
this.stepsCompleted.travelPlan = completed;
|
||||
}
|
||||
|
||||
onInsuranceSaved(completed: boolean): void {
|
||||
this.stepsCompleted.insurance = completed;
|
||||
}
|
||||
|
||||
onShippingSaved(completed: boolean): void {
|
||||
this.stepsCompleted.shipping = completed;
|
||||
}
|
||||
|
||||
onDeliveryMethodSaved(completed: boolean): void {
|
||||
this.stepsCompleted.deliveryMethod = completed;
|
||||
}
|
||||
|
||||
onPaymentSaved(completed: boolean): void {
|
||||
this.stepsCompleted.payment = completed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,7 +102,7 @@ export class ApplicationComponent {
|
||||
this.applicationDetailService.createApplicationDetails(applicationDetailData).subscribe({
|
||||
next: (applicationData: any) => {
|
||||
this.notificationService.showSuccess(`Application details added successfully`);
|
||||
this.headerIdCreated.emit(applicationData.HEADERID);
|
||||
this.headerIdCreated.emit(+applicationData.HEADERID);
|
||||
this.applicationDetailsForm.get('name')?.disable();
|
||||
this.disableSaveButton = true;
|
||||
this.isLoading = false;
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-delivery',
|
||||
imports: [],
|
||||
templateUrl: './delivery.component.html',
|
||||
styleUrl: './delivery.component.scss'
|
||||
})
|
||||
export class DeliveryComponent {
|
||||
@Input() headerid: number = 0;
|
||||
@Output() completed = new EventEmitter<boolean>();
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@
|
||||
<mat-step *ngIf="applicationType === 'new'" [completed]="stepsCompleted.goodsSection"
|
||||
[editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Goods Section</ng-template>
|
||||
<app-goods (completed)="onGoodsSectionSaved($event)" [headerid]="headerid"
|
||||
<app-goods (completed)="onGoodsSectionSaved($event)" [headerid]="headerid" [isEditMode]="isEditMode"
|
||||
[userPreferences]="userPreferences">
|
||||
</app-goods>
|
||||
</mat-step>
|
||||
@ -36,33 +36,11 @@
|
||||
</app-travel-plan>
|
||||
</mat-step>
|
||||
|
||||
<!-- Insurance Step -->
|
||||
<mat-step *ngIf="applicationType === 'new' || applicationType === 'extend' || applicationType === 'additional'"
|
||||
[completed]="stepsCompleted.insurance" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Insurance</ng-template>
|
||||
<app-insurance (completed)="onInsuranceSaved($event)" [headerid]="headerid">
|
||||
</app-insurance>
|
||||
</mat-step>
|
||||
|
||||
<!-- Shipping Step -->
|
||||
<!-- Shipping & Payment Step -->
|
||||
<mat-step [completed]="stepsCompleted.shipping" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Shipping</ng-template>
|
||||
<ng-template matStepLabel>Shipping & Payment</ng-template>
|
||||
<app-shipping (completed)="onShippingSaved($event)" [headerid]="headerid">
|
||||
</app-shipping>
|
||||
</mat-step>
|
||||
|
||||
<!-- Delivery Method Step -->
|
||||
<mat-step [completed]="stepsCompleted.deliveryMethod" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Delivery Method</ng-template>
|
||||
<app-delivery (completed)="onDeliveryMethodSaved($event)" [headerid]="headerid">
|
||||
</app-delivery>
|
||||
</mat-step>
|
||||
|
||||
<!-- Payment Step -->
|
||||
<mat-step [completed]="stepsCompleted.payment" [editable]="stepsCompleted.applicationDetail">
|
||||
<ng-template matStepLabel>Payment</ng-template>
|
||||
<app-payment (completed)="onPaymentSaved($event)" [headerid]="headerid">
|
||||
</app-payment>
|
||||
</mat-step>
|
||||
</mat-stepper>
|
||||
</div>
|
||||
@ -7,9 +7,6 @@ import { StepperSelectionEvent } from '@angular/cdk/stepper';
|
||||
import { GoodsComponent } from '../goods/goods.component';
|
||||
import { HolderComponent } from '../holder/holder.component';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { DeliveryComponent } from '../delivery/delivery.component';
|
||||
import { InsuranceComponent } from '../insurance/insurance.component';
|
||||
import { PaymentComponent } from '../payment/payment.component';
|
||||
import { ShippingComponent } from '../shipping/shipping.component';
|
||||
import { TravelPlanComponent } from '../travel-plan/travel-plan.component';
|
||||
import { UserPreferences } from '../../core/models/user-preference';
|
||||
@ -18,8 +15,7 @@ import { UserPreferencesService } from '../../core/services/user-preference.serv
|
||||
@Component({
|
||||
selector: 'app-edit-carnet',
|
||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule,
|
||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, InsuranceComponent,
|
||||
ShippingComponent, DeliveryComponent, PaymentComponent],
|
||||
ApplicationComponent, HolderComponent, GoodsComponent, TravelPlanComponent, ShippingComponent],
|
||||
templateUrl: './edit-carnet.component.html',
|
||||
styleUrl: './edit-carnet.component.scss'
|
||||
})
|
||||
@ -37,10 +33,7 @@ export class EditCarnetComponent {
|
||||
holderSelection: false,
|
||||
goodsSection: false,
|
||||
travelPlan: false,
|
||||
insurance: false,
|
||||
shipping: false,
|
||||
deliveryMethod: false,
|
||||
payment: false
|
||||
shipping: false
|
||||
};
|
||||
|
||||
private route = inject(ActivatedRoute);
|
||||
@ -70,19 +63,7 @@ export class EditCarnetComponent {
|
||||
this.stepsCompleted.travelPlan = completed;
|
||||
}
|
||||
|
||||
onInsuranceSaved(completed: boolean): void {
|
||||
this.stepsCompleted.insurance = completed;
|
||||
}
|
||||
|
||||
onShippingSaved(completed: boolean): void {
|
||||
this.stepsCompleted.shipping = completed;
|
||||
}
|
||||
|
||||
onDeliveryMethodSaved(completed: boolean): void {
|
||||
this.stepsCompleted.deliveryMethod = completed;
|
||||
}
|
||||
|
||||
onPaymentSaved(completed: boolean): void {
|
||||
this.stepsCompleted.payment = completed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@
|
||||
<!-- Value Column -->
|
||||
<ng-container matColumnDef="value">
|
||||
<th mat-header-cell *matHeaderCellDef mat-sort-header>Value</th>
|
||||
<td mat-cell *matCellDef="let item">{{ formatDecimalDisplay(item.value, 2) }}</td>
|
||||
<td mat-cell *matCellDef="let item">{{ formatDecimalDisplay(item.value, 2) | currency}}</td>
|
||||
</ng-container>
|
||||
|
||||
<!-- Country of Origin Column -->
|
||||
|
||||
@ -29,6 +29,7 @@ import { Goods, GoodsItem } from '../../core/models/carnet/goods';
|
||||
export class GoodsComponent {
|
||||
@Input() headerid: number = 0;
|
||||
@Input() userPreferences: UserPreferences = {};
|
||||
@Input() isEditMode: boolean = false;
|
||||
@Output() completed = new EventEmitter<boolean>();
|
||||
|
||||
@ViewChild(MatPaginator) paginator!: MatPaginator;
|
||||
@ -85,10 +86,6 @@ export class GoodsComponent {
|
||||
value: [0, [Validators.required, Validators.min(1), Validators.pattern(/^\d+(\.\d{1,2})?$/)]],
|
||||
countryOfOrigin: ['', Validators.required]
|
||||
});
|
||||
|
||||
this.goodsForm.valueChanges.subscribe(() => {
|
||||
this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0);
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
@ -117,6 +114,7 @@ export class GoodsComponent {
|
||||
});
|
||||
|
||||
this.loadGoodsItems();
|
||||
this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -314,10 +312,10 @@ export class GoodsComponent {
|
||||
return;
|
||||
}
|
||||
|
||||
items.map(item => {
|
||||
item.countryOfOrigin = this.getCountryValue(item.countryOfOrigin);
|
||||
item.unitOfMeasure = this.getUnitOfMeasureValue(item.unitOfMeasure);
|
||||
});
|
||||
// items.map(item => {
|
||||
// item.countryOfOrigin = this.getCountryValue(item.countryOfOrigin);
|
||||
// item.unitOfMeasure = this.getUnitOfMeasureValue(item.unitOfMeasure);
|
||||
// });
|
||||
|
||||
this.goodsService.addGoodsItem(this.headerid, items).subscribe({
|
||||
next: () => {
|
||||
@ -395,7 +393,7 @@ export class GoodsComponent {
|
||||
this.goodsService.saveGoodsData(this.headerid, formData).subscribe({
|
||||
next: () => {
|
||||
this.notificationService.showSuccess('Goods information saved successfully');
|
||||
this.completed.emit(true);
|
||||
this.completed.emit(this.goodsForm.valid && this.dataSource.data.length > 0);
|
||||
},
|
||||
error: (error) => {
|
||||
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to save goods information');
|
||||
|
||||
@ -1 +0,0 @@
|
||||
<p>insurance works!</p>
|
||||
@ -1,12 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-insurance',
|
||||
imports: [],
|
||||
templateUrl: './insurance.component.html',
|
||||
styleUrl: './insurance.component.scss'
|
||||
})
|
||||
export class InsuranceComponent {
|
||||
@Input() headerid: number = 0;
|
||||
@Output() completed = new EventEmitter<boolean>();
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
<p>payment works!</p>
|
||||
@ -1,12 +0,0 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-payment',
|
||||
imports: [],
|
||||
templateUrl: './payment.component.html',
|
||||
styleUrl: './payment.component.scss'
|
||||
})
|
||||
export class PaymentComponent {
|
||||
@Input() headerid: number = 0;
|
||||
@Output() completed = new EventEmitter<boolean>();
|
||||
}
|
||||
@ -1 +1,302 @@
|
||||
<p>shipping works!</p>
|
||||
<div class="shipping-container">
|
||||
<form [formGroup]="shippingForm" (ngSubmit)="onSubmit()">
|
||||
<!-- Insurance Section -->
|
||||
<div class="section">
|
||||
<h3>Insurance & Bond</h3>
|
||||
<div class="checkbox-group">
|
||||
<mat-checkbox labelPosition="before" formControlName="needsBond">Do you need Bond from
|
||||
us?</mat-checkbox>
|
||||
<mat-checkbox labelPosition="before" formControlName="needsInsurance">Do you need insurance for your
|
||||
goods?</mat-checkbox>
|
||||
<mat-checkbox labelPosition="before" formControlName="needsLostDocProtection">Do you need Lost document
|
||||
protection?</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Shipping Section -->
|
||||
<div class="section">
|
||||
<h3>Ship To</h3>
|
||||
<mat-radio-group formControlName="shipTo" class="radio-group" (change)="onShipToChange($event)">
|
||||
<mat-radio-button value="preparer">Preparer</mat-radio-button>
|
||||
<mat-radio-button value="holder">Holder</mat-radio-button>
|
||||
<mat-radio-button value="thirdParty">3rd Party</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
<mat-card appearance="outlined" *ngIf="!showAddressForm && !showContactForm">
|
||||
<mat-card-content>
|
||||
<p>{{getAddressLabel()}}</p>
|
||||
</mat-card-content>
|
||||
<mat-card-actions>
|
||||
<button mat-button (click)="editAddressForm()">Edit</button>
|
||||
</mat-card-actions>
|
||||
</mat-card>
|
||||
<div *ngIf="showAddressForm" class="address-form" formGroupName="address">
|
||||
<h4>Shipping Address</h4>
|
||||
|
||||
<!-- Address Information -->
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline" class="address1">
|
||||
<mat-label>Address Line 1</mat-label>
|
||||
<input matInput formControlName="address1" required>
|
||||
<mat-error *ngIf="shippingForm.get('address.address1')?.errors?.['required']">
|
||||
Address is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('address.address1')?.errors?.['maxlength']">
|
||||
Maximum 100 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline" class="address2">
|
||||
<mat-label>Address Line 2 (Optional)</mat-label>
|
||||
<input matInput formControlName="address2">
|
||||
<mat-error *ngIf="shippingForm.get('address.address2')?.errors?.['maxlength']">
|
||||
Maximum 100 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Location Information -->
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline" class="city">
|
||||
<mat-label>City</mat-label>
|
||||
<input matInput formControlName="city" required>
|
||||
<mat-error *ngIf="shippingForm.get('address.city')?.errors?.['required']">
|
||||
City is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('address.city')?.errors?.['maxlength']">
|
||||
Maximum 50 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="country">
|
||||
<mat-label>Country</mat-label>
|
||||
<mat-select formControlName="country" required
|
||||
(selectionChange)="onCountryChange($event.value)">
|
||||
<mat-option *ngFor="let country of countries" [value]="country.value">
|
||||
{{ country.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="shippingForm.get('address.country')?.errors?.['required']">
|
||||
Country is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="state">
|
||||
<mat-label>State/Province</mat-label>
|
||||
<mat-select formControlName="state" required>
|
||||
<mat-option *ngFor="let state of states" [value]="state.value">
|
||||
{{ state.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="shippingForm.get('address.state')?.errors?.['required']">
|
||||
State is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="zip">
|
||||
<mat-label>ZIP/Postal Code</mat-label>
|
||||
<input matInput formControlName="zip" required>
|
||||
<mat-error *ngIf="shippingForm.get('address.zip')?.errors?.['required']">
|
||||
ZIP/Postal code is required
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="shippingForm.get('address.country')?.value === 'US' && shippingForm.get('address.zip')?.touched && shippingForm.get('address.zip')?.errors?.['invalidUSZip']">
|
||||
Please enter a valid 5-digit US ZIP code
|
||||
</mat-error>
|
||||
<mat-error
|
||||
*ngIf="shippingForm.get('address.country')?.value === 'CA' && shippingForm.get('address.zip')?.touched && shippingForm.get('address.zip')?.errors?.['invalidCanadaPostal']">
|
||||
Please enter a valid postal code (e.g., A1B2C3)
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form-actions" *ngIf="showAddressForm && shippingForm.get('shipTo')?.value !== 'thirdParty'">
|
||||
<button mat-button type="button" (click)="cancelEditAddressForm()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="showContactForm" class="contact-form" formGroupName="contact">
|
||||
<h4>Contact Information</h4>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>First Name</mat-label>
|
||||
<input matInput formControlName="firstName" required>
|
||||
<mat-icon matSuffix>person</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.firstName')?.errors?.['required']">
|
||||
First name is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.firstName')?.errors?.['maxlength']">
|
||||
Maximum 50 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="small-field">
|
||||
<mat-label>Middle Initial</mat-label>
|
||||
<input matInput formControlName="middleInitial" maxlength="1">
|
||||
<mat-error *ngIf="shippingForm.get('contact.middleInitial')?.errors?.['maxlength']">
|
||||
Only 1 character allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Last Name</mat-label>
|
||||
<input matInput formControlName="lastName" required>
|
||||
<mat-icon matSuffix>person</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.lastName')?.errors?.['required']">
|
||||
Last name is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.lastName')?.errors?.['maxlength']">
|
||||
Maximum 50 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Title</mat-label>
|
||||
<input matInput formControlName="title" required>
|
||||
<mat-icon matSuffix>work</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.title')?.errors?.['required']">
|
||||
Title is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.title')?.errors?.['maxlength']">
|
||||
Maximum 100 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Phone</mat-label>
|
||||
<input matInput formControlName="phone" required>
|
||||
<mat-icon matSuffix>phone</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.phone')?.errors?.['required']">
|
||||
Phone is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.phone')?.errors?.['pattern']">
|
||||
Please enter a valid phone number (10-15 digits)
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Mobile</mat-label>
|
||||
<input matInput formControlName="mobile">
|
||||
<mat-icon matSuffix>smartphone</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.mobile')?.errors?.['required']">
|
||||
Mobile is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.mobile')?.errors?.['pattern']">
|
||||
Please enter a valid mobile number (10-15 digits)
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Fax</mat-label>
|
||||
<input matInput formControlName="fax">
|
||||
<mat-icon matSuffix>fax</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.fax')?.errors?.['pattern']">
|
||||
Please enter a valid fax number (10-15 digits)
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Email</mat-label>
|
||||
<input matInput formControlName="email" required>
|
||||
<mat-icon matSuffix>email</mat-icon>
|
||||
<mat-error *ngIf="shippingForm.get('contact.email')?.errors?.['required']">
|
||||
Email is required
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.email')?.errors?.['email']">
|
||||
Please enter a valid email address
|
||||
</mat-error>
|
||||
<mat-error *ngIf="shippingForm.get('contact.email')?.errors?.['maxlength']">
|
||||
Maximum 100 characters allowed
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Reference Number</mat-label>
|
||||
<input matInput formControlName="refNumber">
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Notes</mat-label>
|
||||
<textarea matInput formControlName="notes" rows="2"></textarea>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delivery Section -->
|
||||
<div class="section">
|
||||
<h3>Delivery Method</h3>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Delivery Type</mat-label>
|
||||
<mat-select formControlName="deliveryType" required>
|
||||
<mat-option *ngFor="let deliveryType of deliveryTypes" [value]="deliveryType.value">
|
||||
{{ deliveryType.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="shippingForm.get('deliveryType')?.errors?.['required']">
|
||||
Delivery Type is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Delivery Method</mat-label>
|
||||
<mat-select formControlName="deliveryMethod" required>
|
||||
<mat-option *ngFor="let deliveryMethod of deliveryMethods" [value]="deliveryMethod.value">
|
||||
{{ deliveryMethod.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="shippingForm.get('deliveryMethod')?.errors?.['required']">
|
||||
Delivery Method is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<div *ngIf="shippingForm.get('deliveryMethod')?.value === 'customerCourier'" class="form-row">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Courier Account Number</mat-label>
|
||||
<input matInput formControlName="courierAccount">
|
||||
<mat-error>Required when using customer courier</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Payment Section -->
|
||||
<div class="section">
|
||||
<h3>Payment Method</h3>
|
||||
<div class="form-row">
|
||||
<mat-form-field appearance="outline">
|
||||
<mat-label>Payment Method</mat-label>
|
||||
<mat-select formControlName="paymentMethod" required>
|
||||
<mat-option *ngFor="let paymentType of paymentTypes" [value]="paymentType.value">
|
||||
{{ paymentType.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
<mat-error *ngIf="shippingForm.get('paymentMethod')?.errors?.['required']">
|
||||
Payment Method is required
|
||||
</mat-error>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<!-- <div class="form-row">
|
||||
<mat-form-field appearance="outline" class="full-width">
|
||||
<mat-label>Payment Notes</mat-label>
|
||||
<textarea matInput formControlName="notes" rows="2"></textarea>
|
||||
</mat-form-field>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button mat-raised-button color="primary" type="submit" [disabled]="shippingForm.invalid || isLoading">
|
||||
<span *ngIf="!isLoading">Save</span>
|
||||
<mat-spinner *ngIf="isLoading" diameter="24"></mat-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -0,0 +1,76 @@
|
||||
.shipping-container {
|
||||
padding: 16px;
|
||||
|
||||
.section {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 4px;
|
||||
|
||||
h3 {
|
||||
margin: 0px 0px 16px 0px;
|
||||
color: var(--mat-sys-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 16px 0 8px;
|
||||
color: var(--mat-sys-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mat-mdc-card-content:first-child {
|
||||
padding: 0 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.radio-group {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
mat-form-field {
|
||||
flex: 1;
|
||||
margin-bottom: 6px;
|
||||
|
||||
&.full-width {
|
||||
flex: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.small-field {
|
||||
max-width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 16px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.shipping-container {
|
||||
.form-row {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,12 +1,376 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
|
||||
import { ReactiveFormsModule, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { NotificationService } from '../../core/services/common/notification.service';
|
||||
import { AngularMaterialModule } from '../../shared/module/angular-material.module';
|
||||
import { ShippingService } from '../../core/services/carnet/shipping.service';
|
||||
import { ApiErrorHandlerService } from '../../core/services/common/api-error-handler.service';
|
||||
import { CommonService } from '../../core/services/common/common.service';
|
||||
import { Shipping } from '../../core/models/carnet/shipping';
|
||||
import { Country } from '../../core/models/country';
|
||||
import { State } from '../../core/models/state';
|
||||
import { ZipCodeValidator } from '../../shared/validators/zipcode-validator';
|
||||
import { Subject, takeUntil } from 'rxjs';
|
||||
import { DeliveryType } from '../../core/models/delivery-type';
|
||||
import { DeliveryMethod } from '../../core/models/delivery-method';
|
||||
import { PaymentType } from '../../core/models/payment-type';
|
||||
|
||||
@Component({
|
||||
selector: 'app-shipping',
|
||||
imports: [],
|
||||
imports: [AngularMaterialModule, CommonModule, ReactiveFormsModule],
|
||||
templateUrl: './shipping.component.html',
|
||||
styleUrl: './shipping.component.scss'
|
||||
})
|
||||
export class ShippingComponent {
|
||||
@Input() headerid: number = 0;
|
||||
@Input() isEditMode = false;
|
||||
@Output() completed = new EventEmitter<boolean>();
|
||||
}
|
||||
|
||||
private fb = inject(FormBuilder);
|
||||
private shippingService = inject(ShippingService);
|
||||
private notificationService = inject(NotificationService);
|
||||
private errorHandler = inject(ApiErrorHandlerService);
|
||||
private commonService = inject(CommonService);
|
||||
|
||||
shippingForm: FormGroup;
|
||||
isLoading = false;
|
||||
showAddressForm = false;
|
||||
showContactForm = false;
|
||||
|
||||
countriesHasStates = ['US', 'CA', 'MX'];
|
||||
countries: Country[] = [];
|
||||
states: State[] = [];
|
||||
deliveryTypes: DeliveryType[] = [];
|
||||
deliveryMethods: DeliveryMethod[] = [];
|
||||
paymentTypes: PaymentType[] = [];
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
// preparer contact and address mock data
|
||||
preparerContact = {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
middleInitial: 'A',
|
||||
title: 'Mr.',
|
||||
phone: '1234567890',
|
||||
mobile: '0987654321',
|
||||
fax: '1234567890',
|
||||
email: 'j@doe.com',
|
||||
}
|
||||
|
||||
preparerAddress = {
|
||||
address1: '123 Main St',
|
||||
address2: 'Suite 100',
|
||||
city: 'Anytown',
|
||||
state: 'CA',
|
||||
zip: '12345',
|
||||
country: 'US'
|
||||
};
|
||||
|
||||
holderAddress = {
|
||||
address1: '456 Holder St',
|
||||
address2: 'Apt 200',
|
||||
city: 'Othertown',
|
||||
state: 'NY',
|
||||
zip: '67890',
|
||||
country: 'US'
|
||||
};
|
||||
|
||||
holderContact = {
|
||||
firstName: 'Jane',
|
||||
lastName: 'Smith',
|
||||
middleInitial: 'B',
|
||||
title: 'Ms.',
|
||||
phone: '2345678901',
|
||||
mobile: '1098765432',
|
||||
fax: '2345678901',
|
||||
email: 'jan@sm.cm'
|
||||
};
|
||||
|
||||
constructor() {
|
||||
this.shippingForm = this.fb.group({
|
||||
needsBond: [false],
|
||||
needsInsurance: [false],
|
||||
needsLostDocProtection: [false],
|
||||
shipTo: ['preparer', Validators.required],
|
||||
address: this.fb.group({
|
||||
address1: ['', [Validators.required, Validators.maxLength(100)]],
|
||||
address2: ['', [Validators.maxLength(100)]],
|
||||
city: ['', [Validators.required, Validators.maxLength(50)]],
|
||||
state: ['', Validators.required],
|
||||
country: ['', Validators.required],
|
||||
zip: ['', [Validators.required, ZipCodeValidator('country')]],
|
||||
}),
|
||||
contact: this.fb.group({
|
||||
firstName: ['', [Validators.required, Validators.maxLength(50)]],
|
||||
lastName: ['', [Validators.required, Validators.maxLength(50)]],
|
||||
middleInitial: ['', [Validators.maxLength(1)]],
|
||||
title: ['', [Validators.required, Validators.maxLength(100)]],
|
||||
phone: ['', [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
|
||||
mobile: ['', [Validators.required, Validators.pattern(/^[0-9]{10,15}$/)]],
|
||||
fax: ['', [Validators.pattern(/^[0-9]{10,15}$/)]],
|
||||
email: ['', [Validators.required, Validators.email, Validators.maxLength(100)]],
|
||||
refNumber: [''],
|
||||
notes: ['']
|
||||
}),
|
||||
deliveryType: ['', Validators.required],
|
||||
deliveryMethod: ['', Validators.required],
|
||||
courierAccount: [''],
|
||||
paymentMethod: ['', Validators.required],
|
||||
notes: ['']
|
||||
});
|
||||
|
||||
// Update form validation based on selections
|
||||
// this.shippingForm.get('shipTo')?.valueChanges.subscribe(value => {
|
||||
// this.updateShippingValidation(value);
|
||||
// });
|
||||
|
||||
this.shippingForm.get('deliveryMethod')?.valueChanges.subscribe(value => {
|
||||
const courierControl = this.shippingForm.get('courierAccount');
|
||||
if (value === 'customerCourier') {
|
||||
courierControl?.setValidators([Validators.required]);
|
||||
} else {
|
||||
courierControl?.clearValidators();
|
||||
}
|
||||
courierControl?.updateValueAndValidity();
|
||||
});
|
||||
|
||||
this.shippingForm.valueChanges.subscribe(() => {
|
||||
this.completed.emit(this.shippingForm.valid);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadCountries();
|
||||
this.loadDeliveryTypes();
|
||||
this.loadDeliveryMethods();
|
||||
this.loadPaymentTypes();
|
||||
|
||||
if (this.headerid && this.isEditMode) {
|
||||
this.loadShippingData();
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
onCountryChange(country: string): void {
|
||||
this.shippingForm.get('address.state')?.reset();
|
||||
|
||||
if (country) {
|
||||
this.loadStates(country);
|
||||
}
|
||||
|
||||
this.shippingForm.get('address.zip')?.updateValueAndValidity();
|
||||
}
|
||||
|
||||
loadCountries(): void {
|
||||
this.commonService.getCountries(0)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (countries) => {
|
||||
this.countries = countries;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Failed to load countries', error);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadDeliveryTypes(): void {
|
||||
this.commonService.getDeliveryTypes(0)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (deliveryTypes) => {
|
||||
this.deliveryTypes = deliveryTypes;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Failed to load delivery types', error);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadDeliveryMethods(): void {
|
||||
this.commonService.getDeliveryMethods(0)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (deliveryMethods) => {
|
||||
this.deliveryMethods = deliveryMethods;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Failed to load delivery methods', error);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadPaymentTypes(): void {
|
||||
this.commonService.getPaymentTypes(0)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (paymentTypes) => {
|
||||
this.paymentTypes = paymentTypes;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Failed to load payment types', error);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadStates(country: string): void {
|
||||
this.isLoading = true;
|
||||
country = this.countriesHasStates.includes(country) ? country : 'FN';
|
||||
this.commonService.getStates(country, 0)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (states) => {
|
||||
this.states = states;
|
||||
const stateControl = this.shippingForm.get('contact.state');
|
||||
if (this.countriesHasStates.includes(country)) {
|
||||
stateControl?.enable();
|
||||
} else {
|
||||
stateControl?.disable();
|
||||
stateControl?.setValue('FN');
|
||||
}
|
||||
this.isLoading = false;
|
||||
},
|
||||
error: (error) => {
|
||||
console.error('Failed to load states', error);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadShippingData(): void {
|
||||
this.isLoading = true;
|
||||
this.shippingService.getShippingData(this.headerid).subscribe({
|
||||
next: (data: Shipping) => {
|
||||
this.patchShippingData(data);
|
||||
this.isLoading = false;
|
||||
},
|
||||
error: (error: any) => {
|
||||
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to load shipping and payments data');
|
||||
this.notificationService.showError(errorMessage);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
patchShippingData(shipping: Shipping): void {
|
||||
this.shippingForm.patchValue({
|
||||
needsBond: shipping.needsBond,
|
||||
needsInsurance: shipping.needsInsurance,
|
||||
needsLostDocProtection: shipping.needsLostDocProtection,
|
||||
shipTo: shipping.shipTo,
|
||||
address: shipping.address,
|
||||
contact: shipping.contact,
|
||||
deliveryType: shipping.deliveryType,
|
||||
deliveryMethod: shipping.deliveryMethod,
|
||||
courierAccount: shipping.courierAccount,
|
||||
paymentMethod: shipping.paymentMethod,
|
||||
notes: shipping.notes
|
||||
});
|
||||
|
||||
if (shipping.address?.country) {
|
||||
this.loadStates(shipping.address?.country);
|
||||
}
|
||||
}
|
||||
|
||||
updateShippingValidation(shipTo: string): void {
|
||||
// const addressGroup = this.shippingForm.get('address') as FormGroup;
|
||||
// const contactGroup = this.shippingForm.get('contact') as FormGroup;
|
||||
|
||||
// if (shipTo === 'thirdParty') {
|
||||
// Object.keys(addressGroup.controls).forEach(key => {
|
||||
// addressGroup.get(key)?.setValidators(Validators.required);
|
||||
// });
|
||||
// Object.keys(contactGroup.controls).forEach(key => {
|
||||
// if (key !== 'middleInitial' && key !== 'fax' && key !== 'notes' && key !== 'refNumber') {
|
||||
// contactGroup.get(key)?.setValidators(Validators.required);
|
||||
// }
|
||||
// });
|
||||
// } else {
|
||||
// Object.keys(addressGroup.controls).forEach(key => {
|
||||
// addressGroup.get(key)?.clearValidators();
|
||||
// });
|
||||
// Object.keys(contactGroup.controls).forEach(key => {
|
||||
// contactGroup.get(key)?.clearValidators();
|
||||
// });
|
||||
// }
|
||||
|
||||
// addressGroup.updateValueAndValidity();
|
||||
// contactGroup.updateValueAndValidity();
|
||||
}
|
||||
|
||||
onSubmit(): void {
|
||||
if (this.shippingForm.invalid) {
|
||||
this.shippingForm.markAllAsTouched();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
const shippingData = this.shippingForm.value;
|
||||
|
||||
this.shippingService.saveShippingDetails(this.headerid, shippingData).subscribe({
|
||||
next: () => {
|
||||
this.notificationService.showSuccess('Shipping & payments information saved successfully');
|
||||
this.completed.emit(true);
|
||||
this.isLoading = false;
|
||||
},
|
||||
error: (error) => {
|
||||
let errorMessage = this.errorHandler.handleApiError(error, 'Failed to save shipping and payment information');
|
||||
this.notificationService.showError(errorMessage);
|
||||
this.isLoading = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getAddressLabel(): string {
|
||||
let shipTo = this.shippingForm.get('shipTo')?.value;
|
||||
|
||||
if (shipTo === 'preparer') {
|
||||
return `${this.preparerContact.firstName} ${this.preparerContact.lastName}, ${this.preparerAddress.address1}, ${this.preparerAddress.city}, ${this.preparerAddress.state}, ${this.preparerAddress.zip}, ${this.preparerAddress.country}`;
|
||||
}
|
||||
|
||||
if (shipTo === 'holder') {
|
||||
return `${this.holderContact.firstName} ${this.holderContact.lastName}, ${this.holderAddress.address1}, ${this.holderAddress.city}, ${this.holderAddress.state}, ${this.holderAddress.zip}, ${this.holderAddress.country}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
editAddressForm(): void {
|
||||
this.showAddressForm = true;
|
||||
let shipTo = this.shippingForm.get('shipTo')?.value;
|
||||
|
||||
if (shipTo === 'preparer') {
|
||||
this.shippingForm.get('address')?.patchValue(this.preparerAddress);
|
||||
this.loadStates(this.preparerAddress.country);
|
||||
} else if (shipTo === 'holder') {
|
||||
this.shippingForm.get('address')?.patchValue(this.holderAddress);
|
||||
this.loadStates(this.preparerAddress.country);
|
||||
}
|
||||
}
|
||||
|
||||
cancelEditAddressForm(): void {
|
||||
this.showAddressForm = false;
|
||||
this.shippingForm.get('address')?.reset();
|
||||
}
|
||||
|
||||
onShipToChange(event: any): void {
|
||||
const shipTo = event.value;
|
||||
this.showAddressForm = false;
|
||||
this.showContactForm = false;
|
||||
|
||||
if (shipTo === 'thirdParty') {
|
||||
this.shippingForm.get('contact')?.reset();
|
||||
this.shippingForm.get('address')?.reset();
|
||||
this.showAddressForm = true;
|
||||
this.showContactForm = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
export interface Delivery {
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
export interface Insurance {
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
export interface Payment {
|
||||
}
|
||||
8
src/app/core/models/carnet/shipping-address.ts
Normal file
8
src/app/core/models/carnet/shipping-address.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface ShippingAddress {
|
||||
address1: string;
|
||||
address2?: string | null;
|
||||
city: string;
|
||||
state: string;
|
||||
country: string;
|
||||
zip: string;
|
||||
}
|
||||
12
src/app/core/models/carnet/shipping-contact.ts
Normal file
12
src/app/core/models/carnet/shipping-contact.ts
Normal file
@ -0,0 +1,12 @@
|
||||
export interface ShippingContact {
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
middleInitial?: string | null;
|
||||
title: string;
|
||||
phone: string;
|
||||
mobile: string;
|
||||
fax?: string | null;
|
||||
email: string;
|
||||
refNumber?: string | null;
|
||||
notes?: string | null;
|
||||
}
|
||||
@ -1,2 +1,23 @@
|
||||
import { ShippingAddress } from "./shipping-address";
|
||||
import { ShippingContact } from "./shipping-contact";
|
||||
|
||||
export interface Shipping {
|
||||
// Insurance details
|
||||
needsBond: boolean;
|
||||
needsInsurance: boolean;
|
||||
needsLostDocProtection: boolean;
|
||||
|
||||
// Shipping details
|
||||
shipTo: string;
|
||||
address?: ShippingAddress;
|
||||
contact?: ShippingContact;
|
||||
|
||||
// Delivery details
|
||||
deliveryType: string;
|
||||
deliveryMethod: string;
|
||||
courierAccount?: string;
|
||||
|
||||
// Payment details
|
||||
paymentMethod: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
5
src/app/core/models/delivery-method.ts
Normal file
5
src/app/core/models/delivery-method.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface DeliveryMethod {
|
||||
name: string;
|
||||
id: string;
|
||||
value: string;
|
||||
}
|
||||
5
src/app/core/models/payment-type.ts
Normal file
5
src/app/core/models/payment-type.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface PaymentType {
|
||||
name: string;
|
||||
id: string;
|
||||
value: string;
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class DeliveryService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PaymentService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@ -1,9 +1,103 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { environment } from '../../../../environments/environment';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { filter, map, Observable } from 'rxjs';
|
||||
import { UserService } from '../common/user.service';
|
||||
import { Shipping } from '../../models/carnet/shipping';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ShippingService {
|
||||
private apiUrl = environment.apiUrl;
|
||||
private apiDb = environment.apiDb;
|
||||
|
||||
constructor() { }
|
||||
private http = inject(HttpClient);
|
||||
private userService = inject(UserService);
|
||||
|
||||
getShippingData(headerid: number): Shipping | any {
|
||||
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetShipPaymentDetailstoEdit/${this.userService.getUserSpid()}/${this.userService.getUser()}/${headerid}`).pipe(
|
||||
filter(response => response.length > 0),
|
||||
map(response => this.mapToShippingData(response?.[0])));
|
||||
}
|
||||
|
||||
private mapToShippingData(shippingDetails: any): Shipping {
|
||||
|
||||
let shippingData: Shipping = {
|
||||
shipTo: shippingDetails.SHIPADDRTYPE,
|
||||
deliveryType: shippingDetails.DELIVERYTYPE,
|
||||
deliveryMethod: shippingDetails.DELIVERYMETHOD,
|
||||
courierAccount: shippingDetails.CUSTCOURIERNO,
|
||||
paymentMethod: shippingDetails.PAYMENTMETHOD,
|
||||
|
||||
notes: shippingDetails.NOTES,
|
||||
needsBond: shippingDetails.INSPROTECTION === 'Y',
|
||||
needsInsurance: shippingDetails.LDIPROTECTION === 'Y',
|
||||
needsLostDocProtection: shippingDetails.LDIPROTECTION === 'Y'
|
||||
};
|
||||
|
||||
if (shippingDetails.address) {
|
||||
shippingData.address = {
|
||||
address1: shippingDetails.ADDRESS1,
|
||||
address2: shippingDetails.ADDRESS2,
|
||||
city: shippingDetails.CITY,
|
||||
state: shippingDetails.STATE,
|
||||
zip: shippingDetails.ZIP,
|
||||
country: shippingDetails.COUNTRY
|
||||
}
|
||||
}
|
||||
|
||||
if (shippingDetails.contact) {
|
||||
shippingData.contact = {
|
||||
firstName: shippingDetails.FIRSTNAME,
|
||||
lastName: shippingDetails.LASTNAME,
|
||||
middleInitial: shippingDetails.MIDDLEINITIAL,
|
||||
title: shippingDetails.TITLE,
|
||||
phone: shippingDetails.PHONENO,
|
||||
mobile: shippingDetails.MOBILENO,
|
||||
fax: shippingDetails.FAXNO,
|
||||
email: shippingDetails.EMAILADDRESS,
|
||||
refNumber: shippingDetails.REFNO,
|
||||
}
|
||||
}
|
||||
|
||||
return shippingData;
|
||||
}
|
||||
|
||||
saveShippingDetails(headerid: number, shippingData: Shipping): Observable<any> {
|
||||
|
||||
const shippingDetails = {
|
||||
P_HEADERID: headerid,
|
||||
P_SHIPTOTYPE: shippingData.shipTo,
|
||||
P_DELIVERYTYPE: shippingData.deliveryType,
|
||||
P_DELIVERYMETHOD: shippingData.deliveryMethod,
|
||||
P_CUSTCOURIERNO: shippingData.courierAccount,
|
||||
P_PAYMENTMETHOD: shippingData.paymentMethod,
|
||||
P_NOTES: shippingData.notes,
|
||||
|
||||
P_FORMOFSECURITY: shippingData.needsBond ? 'Y' : 'N',
|
||||
P_INSPROTECTION: shippingData.needsInsurance ? 'Y' : 'N',
|
||||
P_LDIPROTECTION: shippingData.needsLostDocProtection ? 'Y' : 'N',
|
||||
|
||||
address1: shippingData.address?.address1 || '',
|
||||
address2: shippingData.address?.address2 || null,
|
||||
city: shippingData.address?.city || '',
|
||||
state: shippingData.address?.state || '',
|
||||
zip: shippingData.address?.zip || '',
|
||||
country: shippingData.address?.country || '',
|
||||
|
||||
firstName: shippingData.contact?.firstName || '',
|
||||
lastName: shippingData.contact?.lastName || '',
|
||||
middleInitial: shippingData.contact?.middleInitial || null,
|
||||
title: shippingData.contact?.title || '',
|
||||
phone: shippingData.contact?.phone || '',
|
||||
mobile: shippingData.contact?.mobile || '',
|
||||
fax: shippingData.contact?.fax || null,
|
||||
emailAddress: shippingData.contact?.email || '',
|
||||
refNo: shippingData.contact?.refNumber || '',
|
||||
P_USERID: this.userService.getUser()
|
||||
}
|
||||
|
||||
return this.http.patch(`${this.apiUrl}/${this.apiDb}/UpdateShippingDetails`, shippingDetails);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ import { CargoSurety } from '../../models/cargo-surety';
|
||||
import { CarnetStatus } from '../../models/carnet-status';
|
||||
import { Country } from '../../models/country';
|
||||
import { UnitOfMeasure } from '../../models/unitofmeasure';
|
||||
import { DeliveryMethod } from '../../models/delivery-method';
|
||||
import { PaymentType } from '../../models/payment-type';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@ -156,7 +158,30 @@ export class CommonService {
|
||||
name: item.PARAMDESC,
|
||||
id: item.PARAMID,
|
||||
value: item.PARAMVALUE,
|
||||
color: item.ADDLPARAMVALUE1,
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getDeliveryMethods(_spid: number = 0): Observable<DeliveryMethod[]> {
|
||||
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetParamValues?P_PARAMTYPE=007&P_SPID=0`).pipe(
|
||||
map((response) =>
|
||||
response.map((item) => ({
|
||||
name: item.PARAMDESC,
|
||||
id: item.PARAMID,
|
||||
value: item.PARAMVALUE,
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
getPaymentTypes(_spid: number = 0): Observable<PaymentType[]> {
|
||||
return this.http.get<any[]>(`${this.apiUrl}/${this.apiDb}/GetParamValues?P_PARAMTYPE=008&P_SPID=0`).pipe(
|
||||
map((response) =>
|
||||
response.map((item) => ({
|
||||
name: item.PARAMDESC,
|
||||
id: item.PARAMID,
|
||||
value: item.PARAMVALUE,
|
||||
}))
|
||||
)
|
||||
);
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
<div class="questions-section">
|
||||
<div class="question-row">
|
||||
<mat-radio-group (change)="newCarnet($event)">
|
||||
<mat-label>Do you need a new carnet?</mat-label>
|
||||
<mat-label class="question">Do you need a new carnet?</mat-label>
|
||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
<div class="question-row">
|
||||
<mat-radio-group (change)="additionalSets($event)">
|
||||
<mat-label>Do you need additional sets?</mat-label>
|
||||
<mat-label class="question">Do you need additional sets?</mat-label>
|
||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
@ -27,7 +27,8 @@
|
||||
|
||||
<div class="question-row">
|
||||
<mat-radio-group (change)="duplicateCarnet($event)">
|
||||
<mat-label>Did you lose your carnet? Are you looking for duplicates?</mat-label>
|
||||
<mat-label class="question">Did you lose your carnet? Are you looking for
|
||||
duplicates?</mat-label>
|
||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
@ -35,7 +36,7 @@
|
||||
|
||||
<div class="question-row">
|
||||
<mat-radio-group (change)="extendCarnet($event)">
|
||||
<mat-label>Do you need to extend the carnet?</mat-label>
|
||||
<mat-label class="question">Do you need to extend the carnet?</mat-label>
|
||||
<mat-radio-button [value]="true">Yes</mat-radio-button>
|
||||
<mat-radio-button [value]="false">No</mat-radio-button>
|
||||
</mat-radio-group>
|
||||
|
||||
@ -21,9 +21,12 @@
|
||||
|
||||
.questions-section {
|
||||
flex: 0 0 70%;
|
||||
padding: 24px 0px;
|
||||
margin-bottom: 24px;
|
||||
padding: 12px 16px;
|
||||
margin-bottom: 46px;
|
||||
margin-left: 1rem;
|
||||
margin-top: 24px;
|
||||
background: var(--mat-sys-surface);
|
||||
border-radius: 4px;
|
||||
|
||||
.question-row {
|
||||
margin-bottom: 1rem;
|
||||
@ -32,6 +35,15 @@
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
.question {
|
||||
color: var(--mat-sys-on-surface);
|
||||
font-family: var(--mat-sys-body-medium-font);
|
||||
line-height: var(--mat-sys-body-medium-line-height);
|
||||
font-size: var(--mat-sys-body-medium-size);
|
||||
letter-spacing: var(--mat-sys-body-medium-tracking);
|
||||
font-weight: var(--mat-sys-medium-font-weight);
|
||||
}
|
||||
|
||||
mat-radio-button {
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user