| @@ -1870,14 +1870,10 @@ components: | |||||
| deprecated: false | deprecated: false | ||||
| properties: | properties: | ||||
| zone: | zone: | ||||
| readOnly: true | |||||
| type: string | |||||
| format: iri-reference | |||||
| example: 'https://example.com/' | |||||
| $ref: '#/components/schemas/Zone' | |||||
| name: | name: | ||||
| type: string | type: string | ||||
| zoneName: | |||||
| readOnly: true | |||||
| code: | |||||
| type: string | type: string | ||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| @@ -1887,6 +1883,7 @@ components: | |||||
| format: date-time | format: date-time | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| Location.jsonld: | Location.jsonld: | ||||
| type: object | type: object | ||||
| description: '' | description: '' | ||||
| @@ -1916,12 +1913,10 @@ components: | |||||
| readOnly: true | readOnly: true | ||||
| type: string | type: string | ||||
| zone: | zone: | ||||
| readOnly: true | |||||
| $ref: '#/components/schemas/Zone.jsonld' | $ref: '#/components/schemas/Zone.jsonld' | ||||
| name: | name: | ||||
| type: string | type: string | ||||
| zoneName: | |||||
| readOnly: true | |||||
| code: | |||||
| type: string | type: string | ||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| @@ -1931,6 +1926,7 @@ components: | |||||
| format: date-time | format: date-time | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| MediaObject.jsonld-media_object.read: | MediaObject.jsonld-media_object.read: | ||||
| type: object | type: object | ||||
| description: '' | description: '' | ||||
| @@ -1973,9 +1969,12 @@ components: | |||||
| deprecated: false | deprecated: false | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| properties: | properties: | ||||
| name: | name: | ||||
| type: string | type: string | ||||
| code: | |||||
| type: string | |||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| type: | type: | ||||
| @@ -1988,6 +1987,7 @@ components: | |||||
| deprecated: false | deprecated: false | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| properties: | properties: | ||||
| '@context': | '@context': | ||||
| readOnly: true | readOnly: true | ||||
| @@ -2014,6 +2014,8 @@ components: | |||||
| type: string | type: string | ||||
| name: | name: | ||||
| type: string | type: string | ||||
| code: | |||||
| type: string | |||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| type: | type: | ||||
| @@ -2604,14 +2606,14 @@ components: | |||||
| deprecated: false | deprecated: false | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| properties: | properties: | ||||
| name: | name: | ||||
| type: string | type: string | ||||
| company: | |||||
| readOnly: true | |||||
| code: | |||||
| type: string | type: string | ||||
| format: iri-reference | |||||
| example: 'https://example.com/' | |||||
| company: | |||||
| $ref: '#/components/schemas/ShippingCompany' | |||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| type: | type: | ||||
| @@ -2624,6 +2626,7 @@ components: | |||||
| deprecated: false | deprecated: false | ||||
| required: | required: | ||||
| - name | - name | ||||
| - code | |||||
| properties: | properties: | ||||
| '@context': | '@context': | ||||
| readOnly: true | readOnly: true | ||||
| @@ -2650,8 +2653,9 @@ components: | |||||
| type: string | type: string | ||||
| name: | name: | ||||
| type: string | type: string | ||||
| code: | |||||
| type: string | |||||
| company: | company: | ||||
| readOnly: true | |||||
| $ref: '#/components/schemas/ShippingCompany.jsonld' | $ref: '#/components/schemas/ShippingCompany.jsonld' | ||||
| createdAt: | createdAt: | ||||
| readOnly: true | readOnly: true | ||||
| @@ -118,4 +118,33 @@ export class SearchSelectComponent implements OnInit, AfterViewInit { | |||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| ]; | ]; | ||||
| } | } | ||||
| public static getDefaultColDefShippingCompanies(subResource?: string): ListColDefinition[] { | |||||
| return [ | |||||
| { | |||||
| name: 'name', | |||||
| text: 'common.name', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| field: 'name', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | |||||
| { | |||||
| name: 'code', | |||||
| text: 'common.code', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| field: 'code', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | |||||
| { | |||||
| name: 'createdAt', | |||||
| text: 'common.created_at', | |||||
| type: ListComponent.COLUMN_TYPE_DATE, | |||||
| field: 'createdAt', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_DATE, | |||||
| } as ListColDefinition, | |||||
| ]; | |||||
| } | |||||
| } | } | ||||
| @@ -3,14 +3,14 @@ import { FormGroup, FormControl, Validators } from '@angular/forms'; | |||||
| export const locationForm = new FormGroup({ | export const locationForm = new FormGroup({ | ||||
| zone: new FormControl(null, []), | zone: new FormControl(null, []), | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| zoneName: new FormControl(null, []), | |||||
| code: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| export const locationJsonldForm = new FormGroup({ | export const locationJsonldForm = new FormGroup({ | ||||
| zone: new FormControl(null, []), | zone: new FormControl(null, []), | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| zoneName: new FormControl(null, []), | |||||
| code: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| @@ -20,11 +20,13 @@ export const mediaObjectJsonldMediaObjectReadForm = new FormGroup({ | |||||
| export const shippingCompanyForm = new FormGroup({ | export const shippingCompanyForm = new FormGroup({ | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| code: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| export const shippingCompanyJsonldForm = new FormGroup({ | export const shippingCompanyJsonldForm = new FormGroup({ | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| code: new FormControl(null, [Validators.required]), | |||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| @@ -140,12 +142,14 @@ export const userTripWorkLogJsonldForm = new FormGroup({ | |||||
| export const vesselForm = new FormGroup({ | export const vesselForm = new FormGroup({ | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| code: new FormControl(null, [Validators.required]), | |||||
| company: new FormControl(null, []), | company: new FormControl(null, []), | ||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| export const vesselJsonldForm = new FormGroup({ | export const vesselJsonldForm = new FormGroup({ | ||||
| name: new FormControl(null, [Validators.required]), | name: new FormControl(null, [Validators.required]), | ||||
| code: new FormControl(null, [Validators.required]), | |||||
| company: new FormControl(null, []), | company: new FormControl(null, []), | ||||
| createdAt: new FormControl(null, []) | createdAt: new FormControl(null, []) | ||||
| }); | }); | ||||
| @@ -20,7 +20,7 @@ import {LocationNewComponent} from "@app/_views/location/location-new/location-n | |||||
| export class LocationListComponent implements OnInit, AfterViewInit { | export class LocationListComponent implements OnInit, AfterViewInit { | ||||
| @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | ||||
| protected readonly LocationNewComponent = LocationNewComponent; | |||||
| protected listColDefinitions!: ListColDefinition[]; | protected listColDefinitions!: ListColDefinition[]; | ||||
| constructor( | constructor( | ||||
| @@ -38,19 +38,28 @@ export class LocationListComponent implements OnInit, AfterViewInit { | |||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | filterType: FilterBarComponent.FILTER_TYPE_TEXT, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| { | |||||
| name: 'code', | |||||
| text: 'common.code', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| field: 'code', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | |||||
| { | { | ||||
| name: 'zone', | name: 'zone', | ||||
| text: 'model.zone', | text: 'model.zone', | ||||
| type: ListComponent.COLUMN_TYPE_TEXT, | type: ListComponent.COLUMN_TYPE_TEXT, | ||||
| subResource: 'zone', | |||||
| field: 'name', | field: 'name', | ||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | filterType: FilterBarComponent.FILTER_TYPE_TEXT, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| { | { | ||||
| name: 'creationDate', | |||||
| text: 'common.creation_date', | |||||
| name: 'createdAt', | |||||
| text: 'common.created_at', | |||||
| type: ListComponent.COLUMN_TYPE_DATE, | type: ListComponent.COLUMN_TYPE_DATE, | ||||
| field: 'creationDate', | |||||
| field: 'createdAt', | |||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_DATE, | filterType: FilterBarComponent.FILTER_TYPE_DATE, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| @@ -87,6 +96,5 @@ export class LocationListComponent implements OnInit, AfterViewInit { | |||||
| this.router.navigate(['/' + ROUTE_LOCATIONS, this.appHelperService.extractId(location.id)]); | this.router.navigate(['/' + ROUTE_LOCATIONS, this.appHelperService.extractId(location.id)]); | ||||
| } | } | ||||
| protected readonly ZoneNewComponent = ZoneNewComponent; | |||||
| protected readonly LocationNewComponent = LocationNewComponent; | |||||
| } | } | ||||
| @@ -5,20 +5,25 @@ | |||||
| <label for="name" class="form-label">{{ 'common.name' | translate }}*:</label> | <label for="name" class="form-label">{{ 'common.name' | translate }}*:</label> | ||||
| <input type="text" class="form-control" id="name" formControlName="name" required/> | <input type="text" class="form-control" id="name" formControlName="name" required/> | ||||
| </div> | </div> | ||||
| <div class="mb-3"> | |||||
| <label for="code" class="form-label">{{ 'common.code' | translate }}*:</label> | |||||
| <input type="text" class="form-control" id="code" formControlName="code" required/> | |||||
| </div> | |||||
| <div class="mb-3"> | <div class="mb-3"> | ||||
| <label for="zone" class="form-label">{{ 'model.zone' | translate }}:</label> | <label for="zone" class="form-label">{{ 'model.zone' | translate }}:</label> | ||||
| <app-search-select #zoneSearchSelect | |||||
| [formId]="'zoneIri'" | |||||
| [formLabelLangKey]="'model.zone'" | |||||
| [documentForm]="zoneForm" | |||||
| [getDataFunction]="getZones" | |||||
| [displayedDataField]="'name'" | |||||
| [listColDefinitions]="SearchSelectComponent.getDefaultColDefZones()" | |||||
| <app-search-select #locationSearchSelect | |||||
| [formId]="'zone'" | |||||
| [formLabelLangKey]="'model.zone'" | |||||
| [documentForm]="form" | |||||
| [getDataFunction]="getZones" | |||||
| [displayedDataField]="'name'" | |||||
| [listColDefinitions]="zoneColDefinitions" | |||||
| > | > | ||||
| </app-search-select> | </app-search-select> | ||||
| <input id="zone" type="hidden" formControlName="zone"/> | <input id="zone" type="hidden" formControlName="zone"/> | ||||
| </div> | </div> | ||||
| <button type="submit" class="btn btn-primary" [disabled]="form.invalid">{{ 'basic.send' | translate }} | |||||
| <button type="submit" class="btn btn-primary" [disabled]="form.invalid"> | |||||
| {{ 'basic.send' | translate }} | |||||
| </button> | </button> | ||||
| </form> | </form> | ||||
| </div> | </div> | ||||
| @@ -1,28 +1,38 @@ | |||||
| import {Component, EventEmitter, Input, Output} from '@angular/core'; | |||||
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |||||
| import {AbstractCreateDataComponent} from "@app/_interfaces/AbstractCreateDataComponent"; | import {AbstractCreateDataComponent} from "@app/_interfaces/AbstractCreateDataComponent"; | ||||
| import {LocationJsonld, LocationService, ZoneService} from "@app/core/api/v1"; | import {LocationJsonld, LocationService, ZoneService} from "@app/core/api/v1"; | ||||
| import {ModalStatus} from "@app/_helpers/modal.states"; | import {ModalStatus} from "@app/_helpers/modal.states"; | ||||
| import {FormGroup} from "@angular/forms"; | import {FormGroup} from "@angular/forms"; | ||||
| import {locationForm, zoneForm} from "@app/_forms/apiForms"; | |||||
| import {locationForm} from "@app/_forms/apiForms"; | |||||
| import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | ||||
| import {SearchSelectComponent} from "@app/_components/search-select/search-select.component"; | import {SearchSelectComponent} from "@app/_components/search-select/search-select.component"; | ||||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-location-new', | |||||
| templateUrl: './location-new.component.html', | |||||
| styleUrl: './location-new.component.scss' | |||||
| selector: 'app-location-new', | |||||
| templateUrl: './location-new.component.html', | |||||
| styleUrl: './location-new.component.scss' | |||||
| }) | }) | ||||
| export class LocationNewComponent extends AbstractCreateDataComponent<LocationJsonld>{ | |||||
| export class LocationNewComponent extends AbstractCreateDataComponent<LocationJsonld> implements OnInit { | |||||
| @Input() public override data!: LocationJsonld; | @Input() public override data!: LocationJsonld; | ||||
| @Output() public override submit: EventEmitter<ModalStatus> = new EventEmitter<ModalStatus>(); | @Output() public override submit: EventEmitter<ModalStatus> = new EventEmitter<ModalStatus>(); | ||||
| protected readonly SearchSelectComponent = SearchSelectComponent; | |||||
| override form: FormGroup = locationForm; | override form: FormGroup = locationForm; | ||||
| protected zoneColDefinitions: ListColDefinition[]; | |||||
| constructor( | constructor( | ||||
| private locationService: LocationService, | private locationService: LocationService, | ||||
| private zoneService: ZoneService, | private zoneService: ZoneService, | ||||
| ) { | ) { | ||||
| super(); | super(); | ||||
| this.zoneColDefinitions = SearchSelectComponent.getDefaultColDefZones(); | |||||
| } | |||||
| override ngOnInit() { | |||||
| if (this.data) { | |||||
| this.form.patchValue(this.data); | |||||
| } | |||||
| } | } | ||||
| getInitialData(): LocationJsonld { | getInitialData(): LocationJsonld { | ||||
| @@ -39,6 +49,8 @@ export class LocationNewComponent extends AbstractCreateDataComponent<LocationJs | |||||
| onSubmit() { | onSubmit() { | ||||
| if (this.form.valid) { | if (this.form.valid) { | ||||
| console.log(this.form); | |||||
| console.log(this.form.value as LocationJsonld); | |||||
| this.locationService.locationsPost( | this.locationService.locationsPost( | ||||
| this.form.value as LocationJsonld | this.form.value as LocationJsonld | ||||
| ).subscribe( | ).subscribe( | ||||
| @@ -50,6 +62,5 @@ export class LocationNewComponent extends AbstractCreateDataComponent<LocationJs | |||||
| } | } | ||||
| } | } | ||||
| protected readonly zoneForm = zoneForm; | |||||
| protected readonly SearchSelectComponent = SearchSelectComponent; | |||||
| } | |||||
| } | |||||
| @@ -5,5 +5,6 @@ | |||||
| [onNavigateToDetailsFunction]="navigateToZoneDetail" | [onNavigateToDetailsFunction]="navigateToZoneDetail" | ||||
| [onSortFunction]="onSortChange" | [onSortFunction]="onSortChange" | ||||
| [listColDefinitions]="listColDefinitions" | [listColDefinitions]="listColDefinitions" | ||||
| [createDataComponent]="ShippingCompanyNewComponent" | |||||
| ></app-list> | ></app-list> | ||||
| </div> | </div> | ||||
| @@ -10,7 +10,11 @@ import {AppHelperService} from "@app/_helpers/app-helper.service"; | |||||
| import {FilterBarComponent} from "@app/_components/filter-bar/filter-bar.component"; | import {FilterBarComponent} from "@app/_components/filter-bar/filter-bar.component"; | ||||
| import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | ||||
| import {Sort} from "@angular/material/sort"; | import {Sort} from "@angular/material/sort"; | ||||
| import {ROUTE_SHIPPING_COMPANIES, ROUTE_VESSELS} from "@app/app-routing.module"; | |||||
| import {ROUTE_SHIPPING_COMPANIES} from "@app/app-routing.module"; | |||||
| import { | |||||
| ShippingCompanyNewComponent | |||||
| } from "@app/_views/shipping-company/shipping-company-new/shipping-company-new.component"; | |||||
| import {ZoneNewComponent} from "@app/_views/zone/zone-new/zone-new.component"; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-shipping-company-list', | selector: 'app-shipping-company-list', | ||||
| @@ -20,6 +24,7 @@ import {ROUTE_SHIPPING_COMPANIES, ROUTE_VESSELS} from "@app/app-routing.module"; | |||||
| export class ShippingCompanyListComponent { | export class ShippingCompanyListComponent { | ||||
| @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | ||||
| protected readonly ShippingCompanyNewComponent = ShippingCompanyNewComponent; | |||||
| protected listColDefinitions!: ListColDefinition[]; | protected listColDefinitions!: ListColDefinition[]; | ||||
| constructor( | constructor( | ||||
| @@ -36,12 +41,21 @@ export class ShippingCompanyListComponent { | |||||
| field: 'name', | field: 'name', | ||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | filterType: FilterBarComponent.FILTER_TYPE_TEXT, | ||||
| } as ListColDefinition, | |||||
| { | |||||
| name: 'code', | |||||
| text: 'common.code', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| field: 'code', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| { | { | ||||
| name: 'creationDate', | |||||
| text: 'common.creation_date', | |||||
| name: 'createdAt', | |||||
| text: 'common.created_at', | |||||
| type: ListComponent.COLUMN_TYPE_DATE, | type: ListComponent.COLUMN_TYPE_DATE, | ||||
| field: 'creationDate', | |||||
| field: 'createdAt', | |||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_DATE, | filterType: FilterBarComponent.FILTER_TYPE_DATE, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| @@ -77,4 +91,5 @@ export class ShippingCompanyListComponent { | |||||
| const shippingCompany: ShippingCompanyJsonld = element as ShippingCompanyJsonld; | const shippingCompany: ShippingCompanyJsonld = element as ShippingCompanyJsonld; | ||||
| this.router.navigate(['/' + ROUTE_SHIPPING_COMPANIES, this.appHelperService.extractId(shippingCompany.id)]); | this.router.navigate(['/' + ROUTE_SHIPPING_COMPANIES, this.appHelperService.extractId(shippingCompany.id)]); | ||||
| } | } | ||||
| protected readonly ZoneNewComponent = ZoneNewComponent; | |||||
| } | } | ||||
| @@ -0,0 +1,11 @@ | |||||
| <h2>{{ 'basic.new' | translate }} {{ 'model.shipping_company' | translate }}</h2> | |||||
| <div class="spt-form"> | |||||
| <form [formGroup]="form" (ngSubmit)="onSubmit()"> | |||||
| <div class="mb-3"> | |||||
| <label for="name" class="form-label">{{ 'common.name' | translate }}*:</label> | |||||
| <input type="text" class="form-control" id="name" formControlName="name" required/> | |||||
| </div> | |||||
| <button type="submit" class="btn btn-primary" [disabled]="form.invalid">{{ 'basic.send' | translate }} | |||||
| </button> | |||||
| </form> | |||||
| </div> | |||||
| @@ -0,0 +1,23 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { ShippingCompanyNewComponent } from './shipping-company-new.component'; | |||||
| describe('ShippingCompanyNewComponent', () => { | |||||
| let component: ShippingCompanyNewComponent; | |||||
| let fixture: ComponentFixture<ShippingCompanyNewComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [ShippingCompanyNewComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(ShippingCompanyNewComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,41 @@ | |||||
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |||||
| import {AbstractCreateDataComponent} from "@app/_interfaces/AbstractCreateDataComponent"; | |||||
| import {LocationJsonld, ShippingCompanyJsonld, ShippingCompanyService} from "@app/core/api/v1"; | |||||
| import {ModalStatus} from "@app/_helpers/modal.states"; | |||||
| import {FormGroup} from "@angular/forms"; | |||||
| import {shippingCompanyForm} from "@app/_forms/apiForms"; | |||||
| @Component({ | |||||
| selector: 'app-shipping-company-new', | |||||
| templateUrl: './shipping-company-new.component.html', | |||||
| styleUrl: './shipping-company-new.component.scss' | |||||
| }) | |||||
| export class ShippingCompanyNewComponent extends AbstractCreateDataComponent<ShippingCompanyJsonld> implements OnInit { | |||||
| @Input() public override data!: ShippingCompanyJsonld; | |||||
| @Output() public override submit: EventEmitter<ModalStatus> = new EventEmitter<ModalStatus>(); | |||||
| override form: FormGroup = shippingCompanyForm; | |||||
| constructor( | |||||
| private shippingCompanyService: ShippingCompanyService | |||||
| ) { | |||||
| super(); | |||||
| } | |||||
| getInitialData(): ShippingCompanyJsonld { | |||||
| return {} as ShippingCompanyJsonld; | |||||
| } | |||||
| onSubmit() { | |||||
| if (this.form.valid) { | |||||
| this.shippingCompanyService.shippingCompaniesPost( | |||||
| this.form.value as ShippingCompanyJsonld | |||||
| ).subscribe( | |||||
| data => { | |||||
| this.form.reset(); | |||||
| this.submit.emit(ModalStatus.Submitted); | |||||
| } | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -5,5 +5,6 @@ | |||||
| [onNavigateToDetailsFunction]="navigateToVesselDetail" | [onNavigateToDetailsFunction]="navigateToVesselDetail" | ||||
| [onSortFunction]="onSortChange" | [onSortFunction]="onSortChange" | ||||
| [listColDefinitions]="listColDefinitions" | [listColDefinitions]="listColDefinitions" | ||||
| [createDataComponent]="VesselNewComponent" | |||||
| ></app-list> | ></app-list> | ||||
| </div> | </div> | ||||
| @@ -8,6 +8,7 @@ import {FilterBarComponent} from "@app/_components/filter-bar/filter-bar.compone | |||||
| import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | ||||
| import {Sort} from "@angular/material/sort"; | import {Sort} from "@angular/material/sort"; | ||||
| import {ROUTE_VESSELS} from "@app/app-routing.module"; | import {ROUTE_VESSELS} from "@app/app-routing.module"; | ||||
| import {VesselNewComponent} from "@app/_views/vessel/vessel-new/vessel-new.component"; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-vessel-list', | selector: 'app-vessel-list', | ||||
| @@ -17,6 +18,7 @@ import {ROUTE_VESSELS} from "@app/app-routing.module"; | |||||
| export class VesselListComponent { | export class VesselListComponent { | ||||
| @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | ||||
| protected readonly VesselNewComponent = VesselNewComponent; | |||||
| protected listColDefinitions!: ListColDefinition[]; | protected listColDefinitions!: ListColDefinition[]; | ||||
| constructor( | constructor( | ||||
| @@ -35,10 +37,27 @@ export class VesselListComponent { | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | filterType: FilterBarComponent.FILTER_TYPE_TEXT, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| { | { | ||||
| name: 'creationDate', | |||||
| text: 'common.creation_date', | |||||
| name: 'code', | |||||
| text: 'common.code', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| field: 'code', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | |||||
| { | |||||
| name: 'shippingCompanyName', | |||||
| text: 'model.shipping_company', | |||||
| type: ListComponent.COLUMN_TYPE_TEXT, | |||||
| subResource: 'company', | |||||
| field: 'name', | |||||
| sortable: true, | |||||
| filterType: FilterBarComponent.FILTER_TYPE_TEXT, | |||||
| } as ListColDefinition, | |||||
| { | |||||
| name: 'createdAt', | |||||
| text: 'common.created_at', | |||||
| type: ListComponent.COLUMN_TYPE_DATE, | type: ListComponent.COLUMN_TYPE_DATE, | ||||
| field: 'creationDate', | |||||
| field: 'createdAt', | |||||
| sortable: true, | sortable: true, | ||||
| filterType: FilterBarComponent.FILTER_TYPE_DATE, | filterType: FilterBarComponent.FILTER_TYPE_DATE, | ||||
| } as ListColDefinition, | } as ListColDefinition, | ||||
| @@ -0,0 +1,25 @@ | |||||
| <h2>{{ 'basic.new' | translate }} {{ 'model.vessel' | translate }}</h2> | |||||
| <div class="spt-form"> | |||||
| <form [formGroup]="form" (ngSubmit)="onSubmit()"> | |||||
| <div class="mb-3"> | |||||
| <label for="name" class="form-label">{{ 'common.name' | translate }}*:</label> | |||||
| <input type="text" class="form-control" id="name" formControlName="name" required/> | |||||
| </div> | |||||
| <div class="mb-3"> | |||||
| <label for="zone" class="form-label">{{ 'model.shipping_company' | translate }}:</label> | |||||
| <app-search-select #shippingCompanySearchSelect | |||||
| [formId]="'company'" | |||||
| [formLabelLangKey]="'model.shipping_company'" | |||||
| [documentForm]="form" | |||||
| [getDataFunction]="getShippingCompanies" | |||||
| [displayedDataField]="'name'" | |||||
| [listColDefinitions]="shippingCompanyColDefinitions" | |||||
| > | |||||
| </app-search-select> | |||||
| <input id="company" type="hidden" formControlName="company"/> | |||||
| </div> | |||||
| <button type="submit" class="btn btn-primary" [disabled]="form.invalid"> | |||||
| {{ 'basic.send' | translate }} | |||||
| </button> | |||||
| </form> | |||||
| </div> | |||||
| @@ -0,0 +1,23 @@ | |||||
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { VesselNewComponent } from './vessel-new.component'; | |||||
| describe('VesselNewComponent', () => { | |||||
| let component: VesselNewComponent; | |||||
| let fixture: ComponentFixture<VesselNewComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [VesselNewComponent] | |||||
| }) | |||||
| .compileComponents(); | |||||
| fixture = TestBed.createComponent(VesselNewComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); | |||||
| @@ -0,0 +1,66 @@ | |||||
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |||||
| import {AbstractCreateDataComponent} from "@app/_interfaces/AbstractCreateDataComponent"; | |||||
| import { | |||||
| ShippingCompanyService, | |||||
| VesselJsonld, | |||||
| VesselService, | |||||
| } from "@app/core/api/v1"; | |||||
| import {ModalStatus} from "@app/_helpers/modal.states"; | |||||
| import {FormGroup} from "@angular/forms"; | |||||
| import {vesselForm} from "@app/_forms/apiForms"; | |||||
| import {ListColDefinition} from "@app/_components/list/list-col-definition"; | |||||
| import {SearchSelectComponent} from "@app/_components/search-select/search-select.component"; | |||||
| import {ListGetDataFunctionType} from "@app/_components/list/list-get-data-function-type"; | |||||
| @Component({ | |||||
| selector: 'app-vessel-new', | |||||
| templateUrl: './vessel-new.component.html', | |||||
| styleUrl: './vessel-new.component.scss' | |||||
| }) | |||||
| export class VesselNewComponent extends AbstractCreateDataComponent<VesselJsonld> implements OnInit { | |||||
| @Input() public override data!: VesselJsonld; | |||||
| @Output() public override submit: EventEmitter<ModalStatus> = new EventEmitter<ModalStatus>(); | |||||
| protected readonly SearchSelectComponent = SearchSelectComponent; | |||||
| override form: FormGroup = vesselForm; | |||||
| protected shippingCompanyColDefinitions: ListColDefinition[]; | |||||
| constructor( | |||||
| private vesselService: VesselService, | |||||
| private shippingCompanyService: ShippingCompanyService, | |||||
| ) { | |||||
| super(); | |||||
| this.shippingCompanyColDefinitions = SearchSelectComponent.getDefaultColDefShippingCompanies(); | |||||
| } | |||||
| override ngOnInit() { | |||||
| if (this.data) { | |||||
| this.form.patchValue(this.data); | |||||
| } | |||||
| } | |||||
| getInitialData(): VesselJsonld { | |||||
| return {} as VesselJsonld; | |||||
| } | |||||
| getShippingCompanies: ListGetDataFunctionType = (index: number, pageSize: number, term?: string) => { | |||||
| return this.shippingCompanyService.shippingCompaniesGetCollection( | |||||
| index, | |||||
| pageSize, | |||||
| term | |||||
| ); | |||||
| } | |||||
| onSubmit() { | |||||
| if (this.form.valid) { | |||||
| this.vesselService.vesselsPost( | |||||
| this.form.value as VesselJsonld | |||||
| ).subscribe( | |||||
| data => { | |||||
| this.form.reset(); | |||||
| this.submit.emit(ModalStatus.Submitted); | |||||
| } | |||||
| ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,4 +1,4 @@ | |||||
| import { Component } from '@angular/core'; | |||||
| import {Component} from '@angular/core'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-vessel', | selector: 'app-vessel', | ||||
| @@ -19,6 +19,7 @@ import {SearchSelectComponent} from "@app/_components/search-select/search-selec | |||||
| export class ZoneListComponent { | export class ZoneListComponent { | ||||
| @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | @ViewChild("listComponent", {static: false}) listComponent!: ListComponent; | ||||
| protected readonly ZoneNewComponent = ZoneNewComponent; | |||||
| protected listColDefinitions!: ListColDefinition[]; | protected listColDefinitions!: ListColDefinition[]; | ||||
| constructor( | constructor( | ||||
| @@ -58,5 +59,5 @@ export class ZoneListComponent { | |||||
| const zone: ZoneJsonld = element as ZoneJsonld; | const zone: ZoneJsonld = element as ZoneJsonld; | ||||
| this.router.navigate(['/' + ROUTE_ZONES, this.appHelperService.extractId(zone.id)]); | this.router.navigate(['/' + ROUTE_ZONES, this.appHelperService.extractId(zone.id)]); | ||||
| } | } | ||||
| protected readonly ZoneNewComponent = ZoneNewComponent; | |||||
| } | } | ||||
| @@ -55,6 +55,8 @@ import { VesselListComponent } from './_views/vessel/vessel-list/vessel-list.com | |||||
| import { ShippingCompanyListComponent } from './_views/shipping-company/shipping-company-list/shipping-company-list.component'; | import { ShippingCompanyListComponent } from './_views/shipping-company/shipping-company-list/shipping-company-list.component'; | ||||
| import { ZoneNewComponent } from './_views/zone/zone-new/zone-new.component'; | import { ZoneNewComponent } from './_views/zone/zone-new/zone-new.component'; | ||||
| import { LocationNewComponent } from './_views/location/location-new/location-new.component'; | import { LocationNewComponent } from './_views/location/location-new/location-new.component'; | ||||
| import { ShippingCompanyNewComponent } from './_views/shipping-company/shipping-company-new/shipping-company-new.component'; | |||||
| import { VesselNewComponent } from './_views/vessel/vessel-new/vessel-new.component'; | |||||
| registerLocaleData(localeDe, 'de-DE'); | registerLocaleData(localeDe, 'de-DE'); | ||||
| @@ -132,6 +134,8 @@ export function HttpLoaderFactory(http: HttpClient) { | |||||
| ShippingCompanyListComponent, | ShippingCompanyListComponent, | ||||
| ZoneNewComponent, | ZoneNewComponent, | ||||
| LocationNewComponent, | LocationNewComponent, | ||||
| ShippingCompanyNewComponent, | |||||
| VesselNewComponent, | |||||
| ], | ], | ||||
| providers: [ | providers: [ | ||||
| {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | {provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}, | ||||
| @@ -1,5 +1,4 @@ | |||||
| .gitignore | .gitignore | ||||
| .openapi-generator-ignore | |||||
| README.md | README.md | ||||
| api.module.ts | api.module.ts | ||||
| api/api.ts | api/api.ts | ||||
| @@ -9,15 +9,16 @@ | |||||
| * https://openapi-generator.tech | * https://openapi-generator.tech | ||||
| * Do not edit the class manually. | * Do not edit the class manually. | ||||
| */ | */ | ||||
| import { Zone } from './zone'; | |||||
| /** | /** | ||||
| * | * | ||||
| */ | */ | ||||
| export interface Location { | export interface Location { | ||||
| readonly zone?: string; | |||||
| zone?: Zone; | |||||
| name: string; | name: string; | ||||
| readonly zoneName?: string; | |||||
| code: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -20,9 +20,9 @@ export interface LocationJsonld { | |||||
| context?: LocationJsonldContext; | context?: LocationJsonldContext; | ||||
| readonly id?: string; | readonly id?: string; | ||||
| readonly type?: string; | readonly type?: string; | ||||
| readonly zone?: ZoneJsonld; | |||||
| zone?: ZoneJsonld; | |||||
| name: string; | name: string; | ||||
| readonly zoneName?: string; | |||||
| code: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -16,6 +16,7 @@ | |||||
| */ | */ | ||||
| export interface ShippingCompany { | export interface ShippingCompany { | ||||
| name: string; | name: string; | ||||
| code: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -20,6 +20,7 @@ export interface ShippingCompanyJsonld { | |||||
| readonly id?: string; | readonly id?: string; | ||||
| readonly type?: string; | readonly type?: string; | ||||
| name: string; | name: string; | ||||
| code: string; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -9,6 +9,7 @@ | |||||
| * https://openapi-generator.tech | * https://openapi-generator.tech | ||||
| * Do not edit the class manually. | * Do not edit the class manually. | ||||
| */ | */ | ||||
| import { ShippingCompany } from './shippingCompany'; | |||||
| /** | /** | ||||
| @@ -16,7 +17,8 @@ | |||||
| */ | */ | ||||
| export interface Vessel { | export interface Vessel { | ||||
| name: string; | name: string; | ||||
| readonly company?: string; | |||||
| code: string; | |||||
| company?: ShippingCompany; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -21,7 +21,8 @@ export interface VesselJsonld { | |||||
| readonly id?: string; | readonly id?: string; | ||||
| readonly type?: string; | readonly type?: string; | ||||
| name: string; | name: string; | ||||
| readonly company?: ShippingCompanyJsonld; | |||||
| code: string; | |||||
| company?: ShippingCompanyJsonld; | |||||
| readonly createdAt?: string | null; | readonly createdAt?: string | null; | ||||
| } | } | ||||
| @@ -12,7 +12,8 @@ | |||||
| "common": | "common": | ||||
| { | { | ||||
| "name": "Name", | "name": "Name", | ||||
| "created_at": "Creation date" | |||||
| "code": "Code", | |||||
| "created_at": "Created at" | |||||
| }, | }, | ||||
| "base_data": | "base_data": | ||||
| { | { | ||||
| @@ -24,7 +25,9 @@ | |||||
| }, | }, | ||||
| "model": { | "model": { | ||||
| "location": "Location", | "location": "Location", | ||||
| "zone": "Zone" | |||||
| "zone": "Zone", | |||||
| "vessel": "Vessel", | |||||
| "shipping_company": "Shipping Company" | |||||
| }, | }, | ||||
| "location": | "location": | ||||
| @@ -1,7 +1,7 @@ | |||||
| name: imaq | name: imaq | ||||
| type: php | type: php | ||||
| docroot: public | docroot: public | ||||
| php_version: "8.2" | |||||
| php_version: "8.3" | |||||
| webserver_type: nginx-fpm | webserver_type: nginx-fpm | ||||
| xdebug_enabled: false | xdebug_enabled: false | ||||
| additional_hostnames: [] | additional_hostnames: [] | ||||
| @@ -0,0 +1,31 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace DoctrineMigrations; | |||||
| use Doctrine\DBAL\Schema\Schema; | |||||
| use Doctrine\Migrations\AbstractMigration; | |||||
| /** | |||||
| * Auto-generated Migration: Please modify to your needs! | |||||
| */ | |||||
| final class Version20241206100317 extends AbstractMigration | |||||
| { | |||||
| public function getDescription(): string | |||||
| { | |||||
| return ''; | |||||
| } | |||||
| public function up(Schema $schema): void | |||||
| { | |||||
| // this up() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE location ADD code VARCHAR(10) NOT NULL'); | |||||
| } | |||||
| public function down(Schema $schema): void | |||||
| { | |||||
| // this down() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE location DROP code'); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace DoctrineMigrations; | |||||
| use Doctrine\DBAL\Schema\Schema; | |||||
| use Doctrine\Migrations\AbstractMigration; | |||||
| /** | |||||
| * Auto-generated Migration: Please modify to your needs! | |||||
| */ | |||||
| final class Version20241206103710 extends AbstractMigration | |||||
| { | |||||
| public function getDescription(): string | |||||
| { | |||||
| return ''; | |||||
| } | |||||
| public function up(Schema $schema): void | |||||
| { | |||||
| // this up() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE shipping_company ADD code VARCHAR(20) NOT NULL'); | |||||
| $this->addSql('CREATE UNIQUE INDEX UNIQ_A9F70F8B77153098 ON shipping_company (code)'); | |||||
| $this->addSql('ALTER TABLE vessel ADD code VARCHAR(20) NOT NULL'); | |||||
| $this->addSql('CREATE UNIQUE INDEX UNIQ_4ED8DCA877153098 ON vessel (code)'); | |||||
| } | |||||
| public function down(Schema $schema): void | |||||
| { | |||||
| // this down() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('DROP INDEX UNIQ_4ED8DCA877153098 ON vessel'); | |||||
| $this->addSql('ALTER TABLE vessel DROP code'); | |||||
| $this->addSql('DROP INDEX UNIQ_A9F70F8B77153098 ON shipping_company'); | |||||
| $this->addSql('ALTER TABLE shipping_company DROP code'); | |||||
| } | |||||
| } | |||||
| @@ -54,9 +54,9 @@ class LocationApi | |||||
| * @var ZoneApi | * @var ZoneApi | ||||
| */ | */ | ||||
| #[ApiProperty( | #[ApiProperty( | ||||
| writable: false, | |||||
| writable: true, | |||||
| readableLink: true, | readableLink: true, | ||||
| writableLink: false, | |||||
| writableLink: true, | |||||
| builtinTypes: [ | builtinTypes: [ | ||||
| new Type( | new Type( | ||||
| 'object', | 'object', | ||||
| @@ -69,8 +69,8 @@ class LocationApi | |||||
| #[Assert\NotBlank] | #[Assert\NotBlank] | ||||
| public string $name; | public string $name; | ||||
| #[ApiProperty(writable: false)] | |||||
| public string $zoneName; | |||||
| #[Assert\NotBlank] | |||||
| public string $code; | |||||
| #[ApiProperty(writable: false)] | #[ApiProperty(writable: false)] | ||||
| public ?\DateTimeImmutable $createdAt = null; | public ?\DateTimeImmutable $createdAt = null; | ||||
| @@ -52,6 +52,9 @@ class ShippingCompanyApi | |||||
| #[Assert\NotBlank] | #[Assert\NotBlank] | ||||
| public string $name; | public string $name; | ||||
| #[Assert\NotBlank] | |||||
| public string $code; | |||||
| #[ApiProperty(writable: false)] | #[ApiProperty(writable: false)] | ||||
| public ?\DateTimeImmutable $createdAt = null; | public ?\DateTimeImmutable $createdAt = null; | ||||
| } | } | ||||
| @@ -53,13 +53,16 @@ class VesselApi | |||||
| #[Assert\NotBlank] | #[Assert\NotBlank] | ||||
| public string $name; | public string $name; | ||||
| #[Assert\NotBlank] | |||||
| public string $code; | |||||
| /** | /** | ||||
| * @var ShippingCompanyApi | * @var ShippingCompanyApi | ||||
| */ | */ | ||||
| #[ApiProperty( | #[ApiProperty( | ||||
| writable: false, | |||||
| writable: true, | |||||
| readableLink: true, | readableLink: true, | ||||
| writableLink: false, | |||||
| writableLink: true, | |||||
| builtinTypes: [ | builtinTypes: [ | ||||
| new Type( | new Type( | ||||
| 'object', | 'object', | ||||
| @@ -0,0 +1,111 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace App\Command\Import; | |||||
| use App\Entity\ShippingCompany; | |||||
| use App\Entity\Vessel; | |||||
| use Doctrine\ORM\EntityManagerInterface; | |||||
| use Symfony\Component\Console\Attribute\AsCommand; | |||||
| use Symfony\Component\Console\Command\Command; | |||||
| use Symfony\Component\Console\Input\InputInterface; | |||||
| use Symfony\Component\Console\Output\OutputInterface; | |||||
| use Symfony\Component\Console\Style\SymfonyStyle; | |||||
| #[AsCommand( | |||||
| name: 'app:create-shipping-test-data', | |||||
| description: 'Creates test data for shipping companies and vessels with unique codes' | |||||
| )] | |||||
| class CreateShippingTestDataCommand extends Command | |||||
| { | |||||
| private array $companyData = [ | |||||
| ['name' => 'Arctic Shipping Lines', 'code' => 'ARCTIC-SL'], | |||||
| ['name' => 'Greenland Marine Transport', 'code' => 'GRE-MAR-TRANS'], | |||||
| ['name' => 'Nordic Sea Carriers', 'code' => 'NORDIC-SEA'], | |||||
| ['name' => 'Polar Route Navigation', 'code' => 'POLAR-ROUTE'], | |||||
| ['name' => 'Royal Arctic Line', 'code' => 'RAL'], | |||||
| ['name' => 'North Atlantic Shipping', 'code' => 'NORTH-ATL'], | |||||
| ['name' => 'Viking Ocean Transport', 'code' => 'VIKING-OT'], | |||||
| ['name' => 'Ice Route Maritime', 'code' => 'ICE-ROUTE'], | |||||
| ['name' => 'Aurora Vessel Operations', 'code' => 'AURORA-VO'], | |||||
| ['name' => 'Baltic Sea Logistics', 'code' => 'BALTIC-LOG'] | |||||
| ]; | |||||
| private array $vesselNames = [ | |||||
| 'Nordic Explorer', | |||||
| 'Arctic Princess', | |||||
| 'Polar Star', | |||||
| 'Northern Light', | |||||
| 'Ice Breaker', | |||||
| 'Aurora', | |||||
| 'Viking Spirit', | |||||
| 'Ocean Pioneer', | |||||
| 'Greenland Express', | |||||
| 'Baltic Voyager' | |||||
| ]; | |||||
| public function __construct( | |||||
| private readonly EntityManagerInterface $entityManager | |||||
| ) { | |||||
| parent::__construct(); | |||||
| } | |||||
| protected function execute(InputInterface $input, OutputInterface $output): int | |||||
| { | |||||
| $io = new SymfonyStyle($input, $output); | |||||
| try { | |||||
| // Shuffle company data to randomize selection | |||||
| shuffle($this->companyData); | |||||
| // Select 7-10 companies randomly | |||||
| $numberOfCompanies = random_int(7, 10); | |||||
| $selectedCompanies = array_slice($this->companyData, 0, $numberOfCompanies); | |||||
| foreach ($selectedCompanies as $companyInfo) { | |||||
| $company = new ShippingCompany($companyInfo['name'], $companyInfo['code']); | |||||
| $this->entityManager->persist($company); | |||||
| // Create 1-3 vessels for each company | |||||
| $numberOfVessels = random_int(1, 3); | |||||
| // Generate unique vessel names and codes | |||||
| for ($i = 0; $i < $numberOfVessels; $i++) { | |||||
| $vesselName = $this->vesselNames[array_rand($this->vesselNames)]; | |||||
| // Create unique vessel code using company code and counter | |||||
| $vesselCode = sprintf( | |||||
| '%s-V%03d', | |||||
| $companyInfo['code'], | |||||
| random_int(1, 999) | |||||
| ); | |||||
| $vessel = new Vessel($company, $vesselName, $vesselCode); | |||||
| $this->entityManager->persist($vessel); | |||||
| $io->writeln(sprintf( | |||||
| 'Created vessel "%s" (%s) for company "%s" (%s)', | |||||
| $vesselName, | |||||
| $vesselCode, | |||||
| $companyInfo['name'], | |||||
| $companyInfo['code'] | |||||
| )); | |||||
| } | |||||
| $io->writeln(sprintf( | |||||
| 'Created company "%s" (%s) with %d vessels', | |||||
| $companyInfo['name'], | |||||
| $companyInfo['code'], | |||||
| $numberOfVessels | |||||
| )); | |||||
| } | |||||
| $this->entityManager->flush(); | |||||
| $io->success(sprintf('Created %d companies with vessels', $numberOfCompanies)); | |||||
| return Command::SUCCESS; | |||||
| } catch (\Exception $e) { | |||||
| $io->error('Error creating test data: ' . $e->getMessage()); | |||||
| return Command::FAILURE; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,117 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace App\Command\Import; | |||||
| use App\Entity\Zone; | |||||
| use App\Entity\Location; | |||||
| use Doctrine\ORM\EntityManagerInterface; | |||||
| use Symfony\Component\Console\Attribute\AsCommand; | |||||
| use Symfony\Component\Console\Command\Command; | |||||
| use Symfony\Component\Console\Input\InputInterface; | |||||
| use Symfony\Component\Console\Output\OutputInterface; | |||||
| use Symfony\Component\Console\Style\SymfonyStyle; | |||||
| #[AsCommand( | |||||
| name: 'app:import-zones-locations', | |||||
| description: 'Import zones and locations from matrix' | |||||
| )] | |||||
| class ImportZonesLocationsCommand extends Command | |||||
| { | |||||
| public function __construct( | |||||
| private readonly EntityManagerInterface $entityManager | |||||
| ) { | |||||
| parent::__construct(); | |||||
| } | |||||
| protected function execute(InputInterface $input, OutputInterface $output): int | |||||
| { | |||||
| $io = new SymfonyStyle($input, $output); | |||||
| // Zone data | |||||
| $zoneData = [ | |||||
| 4 => 'Area 4', | |||||
| 5 => 'Area 5', | |||||
| 6 => 'Area 6', | |||||
| 7 => 'Area 7', | |||||
| ]; | |||||
| // Location data | |||||
| $locationData = [ | |||||
| 4 => [ | |||||
| ['code' => 'TAS', 'name' => 'Tasiilaq'], | |||||
| ['code' => 'UMI', 'name' => 'Umivik'], | |||||
| ['code' => 'SKJ', 'name' => 'Skjoldungen'], | |||||
| ], | |||||
| 5 => [ | |||||
| ['code' => 'PCS', 'name' => 'Prins Chr. Sund'], | |||||
| ['code' => 'NAN', 'name' => 'Nanortalik / Tasermiut fjorden'], | |||||
| ['code' => 'QAQ', 'name' => 'Qaqortoq / Igaliku fjorden'], | |||||
| ['code' => 'NRQ', 'name' => 'Narsaq/Skovfjord/Bredefjord'], | |||||
| ['code' => 'NRQ', 'name' => 'Narsaq - Havnelodsning'], | |||||
| ['code' => 'NSSQ', 'name' => 'Narsarssuaq/Skovfjord/Bredefjord'], | |||||
| ['code' => 'IVI', 'name' => 'Arsuk/Ivigtut/Grønnedal'], | |||||
| ['code' => 'PAA', 'name' => 'Paamiut/Kvanefjord'], | |||||
| ['code' => 'NUU', 'name' => 'Nuuk/Nuuk Fjorden'], | |||||
| ['code' => 'NUU', 'name' => 'Nuuk - Havnelodsning'], | |||||
| ], | |||||
| 6 => [ | |||||
| ['code' => 'MAN', 'name' => 'Maniitsoq/Hamborgsund'], | |||||
| ['code' => 'EVI', 'name' => 'Evighedsfjorden'], | |||||
| ['code' => 'SFJ', 'name' => 'Kangerlussuaq'], | |||||
| ['code' => 'SIS', 'name' => 'Sisimiut'], | |||||
| ['code' => 'SIS', 'name' => 'Sisimiut - Havnelodsning'], | |||||
| ], | |||||
| 7 => [ | |||||
| ['code' => 'AAS', 'name' => 'Aasiaat'], | |||||
| ['code' => 'QEQ', 'name' => 'Qeqertarsuaq'], | |||||
| ['code' => 'QAS', 'name' => 'Qasigiannguit'], | |||||
| ['code' => 'ILU', 'name' => 'Ilulissat/Ilimanaq'], | |||||
| ['code' => 'QER', 'name' => 'Qeqertaq'], | |||||
| ['code' => 'SQQ', 'name' => 'Sarqaq'], | |||||
| ['code' => 'VAI', 'name' => 'Vaigat'], | |||||
| ['code' => 'UUM', 'name' => 'Uummannaq'], | |||||
| ], | |||||
| ]; | |||||
| try { | |||||
| // Import zones | |||||
| $zones = []; | |||||
| foreach ($zoneData as $zoneId => $zoneName) { | |||||
| $zone = new Zone($zoneName); | |||||
| $this->entityManager->persist($zone); | |||||
| $zones[$zoneId] = $zone; | |||||
| $io->writeln(sprintf('Created zone "%s"', $zoneName)); | |||||
| } | |||||
| // Import locations | |||||
| foreach ($locationData as $zoneId => $locations) { | |||||
| $zone = $zones[$zoneId]; | |||||
| foreach ($locations as $locationInfo) { | |||||
| $location = new Location( | |||||
| $zone, | |||||
| $locationInfo['name'], | |||||
| $locationInfo['code'] | |||||
| ); | |||||
| $this->entityManager->persist($location); | |||||
| $io->writeln(sprintf( | |||||
| 'Created location "%s" (%s) in zone "%s"', | |||||
| $locationInfo['name'], | |||||
| $locationInfo['code'], | |||||
| $zone->getName() | |||||
| )); | |||||
| } | |||||
| } | |||||
| $this->entityManager->flush(); | |||||
| $io->success('Import completed successfully'); | |||||
| return Command::SUCCESS; | |||||
| } catch (\Exception $e) { | |||||
| $io->error('Import error: ' . $e->getMessage()); | |||||
| return Command::FAILURE; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -22,6 +22,9 @@ class Location | |||||
| #[ORM\JoinColumn(nullable: false)] | #[ORM\JoinColumn(nullable: false)] | ||||
| private Zone $zone; | private Zone $zone; | ||||
| #[ORM\Column(length: 10)] | |||||
| private string $code; | |||||
| #[ORM\Column(length: 255)] | #[ORM\Column(length: 255)] | ||||
| private string $name; | private string $name; | ||||
| @@ -40,10 +43,11 @@ class Location | |||||
| #[ORM\OneToMany(targetEntity: UserTripWorkLog::class, mappedBy: 'endLocation')] | #[ORM\OneToMany(targetEntity: UserTripWorkLog::class, mappedBy: 'endLocation')] | ||||
| private Collection $endWorkLogs; | private Collection $endWorkLogs; | ||||
| public function __construct(Zone $zone, string $name) | |||||
| public function __construct(Zone $zone, string $name, string $code) | |||||
| { | { | ||||
| $this->zone = $zone; | $this->zone = $zone; | ||||
| $this->name = $name; | $this->name = $name; | ||||
| $this->code = $code; | |||||
| $this->createdAt = new DateTimeImmutable(); | $this->createdAt = new DateTimeImmutable(); | ||||
| $this->tripLocations = new ArrayCollection(); | $this->tripLocations = new ArrayCollection(); | ||||
| $this->userTripLocations = new ArrayCollection(); | $this->userTripLocations = new ArrayCollection(); | ||||
| @@ -78,6 +82,16 @@ class Location | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getCode(): string | |||||
| { | |||||
| return $this->code; | |||||
| } | |||||
| public function setCode(string $code): void | |||||
| { | |||||
| $this->code = $code; | |||||
| } | |||||
| public function getCreatedAt(): DateTimeImmutable | public function getCreatedAt(): DateTimeImmutable | ||||
| { | { | ||||
| return $this->createdAt; | return $this->createdAt; | ||||
| @@ -21,15 +21,19 @@ class ShippingCompany | |||||
| #[ORM\Column(length: 255)] | #[ORM\Column(length: 255)] | ||||
| private string $name; | private string $name; | ||||
| #[ORM\Column(length: 20, unique: true)] | |||||
| private string $code; | |||||
| #[ORM\Column] | #[ORM\Column] | ||||
| private DateTimeImmutable $createdAt; | private DateTimeImmutable $createdAt; | ||||
| #[ORM\OneToMany(targetEntity: Vessel::class, mappedBy: 'company')] | #[ORM\OneToMany(targetEntity: Vessel::class, mappedBy: 'company')] | ||||
| private Collection $vessels; | private Collection $vessels; | ||||
| public function __construct(string $name) | |||||
| public function __construct(string $name, string $code) | |||||
| { | { | ||||
| $this->name = $name; | $this->name = $name; | ||||
| $this->code = $code; | |||||
| $this->createdAt = new DateTimeImmutable(); | $this->createdAt = new DateTimeImmutable(); | ||||
| $this->vessels = new ArrayCollection(); | $this->vessels = new ArrayCollection(); | ||||
| } | } | ||||
| @@ -50,6 +54,16 @@ class ShippingCompany | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getCode(): string | |||||
| { | |||||
| return $this->code; | |||||
| } | |||||
| public function setCode(string $code): void | |||||
| { | |||||
| $this->code = $code; | |||||
| } | |||||
| public function getCreatedAt(): DateTimeImmutable | public function getCreatedAt(): DateTimeImmutable | ||||
| { | { | ||||
| return $this->createdAt; | return $this->createdAt; | ||||
| @@ -25,16 +25,20 @@ class Vessel | |||||
| #[ORM\Column(length: 255)] | #[ORM\Column(length: 255)] | ||||
| private string $name; | private string $name; | ||||
| #[ORM\Column(length: 20, unique: true)] | |||||
| private string $code; | |||||
| #[ORM\Column] | #[ORM\Column] | ||||
| private DateTimeImmutable $createdAt; | private DateTimeImmutable $createdAt; | ||||
| #[ORM\OneToMany(targetEntity: Trip::class, mappedBy: 'vessel')] | #[ORM\OneToMany(targetEntity: Trip::class, mappedBy: 'vessel')] | ||||
| private Collection $trips; | private Collection $trips; | ||||
| public function __construct(ShippingCompany $company, string $name) | |||||
| public function __construct(ShippingCompany $company, string $name, string $code) | |||||
| { | { | ||||
| $this->company = $company; | $this->company = $company; | ||||
| $this->name = $name; | $this->name = $name; | ||||
| $this->code = $code; | |||||
| $this->createdAt = new DateTimeImmutable(); | $this->createdAt = new DateTimeImmutable(); | ||||
| $this->trips = new ArrayCollection(); | $this->trips = new ArrayCollection(); | ||||
| } | } | ||||
| @@ -66,6 +70,16 @@ class Vessel | |||||
| return $this; | return $this; | ||||
| } | } | ||||
| public function getCode(): string | |||||
| { | |||||
| return $this->code; | |||||
| } | |||||
| public function setCode(string $code): void | |||||
| { | |||||
| $this->code = $code; | |||||
| } | |||||
| public function getCreatedAt(): DateTimeImmutable | public function getCreatedAt(): DateTimeImmutable | ||||
| { | { | ||||
| return $this->createdAt; | return $this->createdAt; | ||||
| @@ -33,7 +33,7 @@ class LocationApiToEntityMapper implements MapperInterface | |||||
| } | } | ||||
| // For new locations, we need the zone | // For new locations, we need the zone | ||||
| if (!$dto->zone?->id) { | |||||
| if (!$dto->zone) { | |||||
| throw new \Exception('Zone is required for new locations'); | throw new \Exception('Zone is required for new locations'); | ||||
| } | } | ||||
| @@ -42,7 +42,7 @@ class LocationApiToEntityMapper implements MapperInterface | |||||
| throw new \Exception('Zone not found'); | throw new \Exception('Zone not found'); | ||||
| } | } | ||||
| return new Location($zone, $dto->name); | |||||
| return new Location($zone, $dto->name, $dto->code); | |||||
| } | } | ||||
| public function populate(object $from, object $to, array $context): object | public function populate(object $from, object $to, array $context): object | ||||
| @@ -53,6 +53,15 @@ class LocationApiToEntityMapper implements MapperInterface | |||||
| assert($entity instanceof Location); | assert($entity instanceof Location); | ||||
| $entity->setName($dto->name); | $entity->setName($dto->name); | ||||
| $entity->setCode($dto->code); | |||||
| if ($dto->zone) { | |||||
| $zone = $this->zoneRepository->find($dto->zone->id); | |||||
| if (!$zone) { | |||||
| throw new \Exception('Zone not found'); | |||||
| } | |||||
| $entity->setZone($zone); | |||||
| } | |||||
| return $entity; | return $entity; | ||||
| } | } | ||||
| @@ -36,14 +36,13 @@ class LocationEntityToApiMapper implements MapperInterface | |||||
| assert($dto instanceof LocationApi); | assert($dto instanceof LocationApi); | ||||
| $dto->name = $entity->getName(); | $dto->name = $entity->getName(); | ||||
| $dto->code = $entity->getCode(); | |||||
| $dto->createdAt = $entity->getCreatedAt(); | $dto->createdAt = $entity->getCreatedAt(); | ||||
| $dto->zone = $this->microMapper->map($entity->getZone(), ZoneApi::class, [ | $dto->zone = $this->microMapper->map($entity->getZone(), ZoneApi::class, [ | ||||
| MicroMapperInterface::MAX_DEPTH => 1, | MicroMapperInterface::MAX_DEPTH => 1, | ||||
| ]); | ]); | ||||
| $dto->zoneName = $dto->zone->name; | |||||
| return $dto; | return $dto; | ||||
| } | } | ||||
| } | } | ||||
| @@ -37,6 +37,7 @@ class ShippingCompanyApiToEntityMapper implements MapperInterface | |||||
| assert($entity instanceof ShippingCompany); | assert($entity instanceof ShippingCompany); | ||||
| $entity->setName($dto->name); | $entity->setName($dto->name); | ||||
| $entity->setCode($dto->code); | |||||
| return $entity; | return $entity; | ||||
| } | } | ||||
| @@ -35,6 +35,7 @@ class ShippingCompanyEntityToApiMapper implements MapperInterface | |||||
| assert($dto instanceof ShippingCompanyApi); | assert($dto instanceof ShippingCompanyApi); | ||||
| $dto->name = $entity->getName(); | $dto->name = $entity->getName(); | ||||
| $dto->code = $entity->getCode(); | |||||
| $dto->createdAt = $entity->getCreatedAt(); | $dto->createdAt = $entity->getCreatedAt(); | ||||
| return $dto; | return $dto; | ||||
| @@ -42,7 +42,7 @@ class VesselApiToEntityMapper implements MapperInterface | |||||
| throw new \Exception('ShippingCompany not found'); | throw new \Exception('ShippingCompany not found'); | ||||
| } | } | ||||
| return new Vessel($company, $dto->name); | |||||
| return new Vessel($company, $dto->name, $dto->code); | |||||
| } | } | ||||
| public function populate(object $from, object $to, array $context): object | public function populate(object $from, object $to, array $context): object | ||||
| @@ -53,6 +53,8 @@ class VesselApiToEntityMapper implements MapperInterface | |||||
| assert($entity instanceof Vessel); | assert($entity instanceof Vessel); | ||||
| $entity->setName($dto->name); | $entity->setName($dto->name); | ||||
| $entity->setCode($dto->code); | |||||
| $dto->createdAt = $entity->getCreatedAt(); | |||||
| return $entity; | return $entity; | ||||
| } | } | ||||
| @@ -36,6 +36,7 @@ class VesselEntityToApiMapper implements MapperInterface | |||||
| assert($dto instanceof VesselApi); | assert($dto instanceof VesselApi); | ||||
| $dto->name = $entity->getName(); | $dto->name = $entity->getName(); | ||||
| $dto->code = $entity->getCode(); | |||||
| $dto->createdAt = $entity->getCreatedAt(); | $dto->createdAt = $entity->getCreatedAt(); | ||||
| $dto->company = $this->microMapper->map($entity->getCompany(), ShippingCompanyApi::class, [ | $dto->company = $this->microMapper->map($entity->getCompany(), ShippingCompanyApi::class, [ | ||||