diff --git a/matsen-tool/src/app/app.module.ts b/matsen-tool/src/app/app.module.ts
index 998d79c..621d1e6 100644
--- a/matsen-tool/src/app/app.module.ts
+++ b/matsen-tool/src/app/app.module.ts
@@ -45,6 +45,7 @@ import { NewTaskNoteComponent } from './tasks/new-task-note/new-task-note.compon
import { DocumentsDetailComponent } from './documents/documents-detail/documents-detail.component';
import { SalesComponent } from './sales/sales.component';
import { SalesDetailComponent } from './sales/sales-detail/sales-detail.component';
+import { NewSaleComponent } from './sales/new-sale/new-sale.component';
export function apiConfigFactory(): Configuration {
const params: ConfigurationParameters = {
@@ -110,7 +111,8 @@ export function HttpLoaderFactory(http: HttpClient) {
NewTaskNoteComponent,
DocumentsDetailComponent,
SalesComponent,
- SalesDetailComponent
+ SalesDetailComponent,
+ NewSaleComponent
],
providers: [
{provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true},
diff --git a/matsen-tool/src/app/documents/new-document/new-document.component.html b/matsen-tool/src/app/documents/new-document/new-document.component.html
index b3aac2c..8673075 100644
--- a/matsen-tool/src/app/documents/new-document/new-document.component.html
+++ b/matsen-tool/src/app/documents/new-document/new-document.component.html
@@ -16,7 +16,7 @@
+ [resultFormatter]="formatter" [editable]="false" (selectItem)="onPartnerSelect($event)"/>
@@ -24,7 +24,7 @@
+ [resultFormatter]="formatter" [editable]="false" (selectItem)="onProductSelect($event)"/>
diff --git a/matsen-tool/src/app/documents/new-document/new-document.component.ts b/matsen-tool/src/app/documents/new-document/new-document.component.ts
index 430f809..69bffba 100644
--- a/matsen-tool/src/app/documents/new-document/new-document.component.ts
+++ b/matsen-tool/src/app/documents/new-document/new-document.component.ts
@@ -82,11 +82,11 @@ export class NewDocumentComponent implements OnInit {
);
}
- protected onAssignedToSelectPartner(selectedItem: any): void {
+ protected onPartnerSelect(selectedItem: any): void {
this.documentForm.get('partner')?.setValue(selectedItem.item.id);
}
- protected onAssignedToSelectProduct(selectedItem: any): void {
+ protected onProductSelect(selectedItem: any): void {
this.documentForm.get('product')?.setValue(selectedItem.item.id);
}
diff --git a/matsen-tool/src/app/sales/new-sale/new-sale.component.html b/matsen-tool/src/app/sales/new-sale/new-sale.component.html
new file mode 100644
index 0000000..0c3b316
--- /dev/null
+++ b/matsen-tool/src/app/sales/new-sale/new-sale.component.html
@@ -0,0 +1,80 @@
+
{{ 'basic.new-sale' | translate }}
+{{ 'basic.edit-sale' | translate }}
+
+
diff --git a/matsen-tool/src/app/sales/new-sale/new-sale.component.scss b/matsen-tool/src/app/sales/new-sale/new-sale.component.scss
new file mode 100644
index 0000000..e69de29
diff --git a/matsen-tool/src/app/sales/new-sale/new-sale.component.spec.ts b/matsen-tool/src/app/sales/new-sale/new-sale.component.spec.ts
new file mode 100644
index 0000000..466a53b
--- /dev/null
+++ b/matsen-tool/src/app/sales/new-sale/new-sale.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { NewSaleComponent } from './new-sale.component';
+
+describe('NewSaleComponent', () => {
+ let component: NewSaleComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [NewSaleComponent]
+ })
+ .compileComponents();
+
+ fixture = TestBed.createComponent(NewSaleComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/matsen-tool/src/app/sales/new-sale/new-sale.component.ts b/matsen-tool/src/app/sales/new-sale/new-sale.component.ts
new file mode 100644
index 0000000..40965b6
--- /dev/null
+++ b/matsen-tool/src/app/sales/new-sale/new-sale.component.ts
@@ -0,0 +1,126 @@
+import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
+import {
+ MediaObjectService,
+ PartnerJsonld,
+ PartnerService,
+ ProductService,
+ SaleJsonld,
+ SaleService
+} from "@app/core/api/v1";
+import {ModalStatus} from "@app/_helpers/modal.states";
+import {FormGroup} from "@angular/forms";
+import {debounceTime, distinctUntilChanged, Observable, OperatorFunction, Subscription, switchMap} from "rxjs";
+import {TranslateService} from "@ngx-translate/core";
+import {FormGroupInitializer} from "@app/_helpers/formgroup.initializer";
+import {saleForm} from "@app/_forms/apiForms";
+import {ApiConverter} from "@app/_helpers/api.converter";
+import {filter, map} from "rxjs/operators";
+
+@Component({
+ selector: 'app-new-sale',
+ templateUrl: './new-sale.component.html',
+ styleUrl: './new-sale.component.scss'
+})
+export class NewSaleComponent implements OnInit {
+ @Input() public sale!: SaleJsonld;
+ @Output() public submit: EventEmitter = new EventEmitter();
+
+ protected saleForm: FormGroup;
+ protected saleSub: Subscription;
+
+ protected formatter = (apiData: any) => apiData.name;
+
+ constructor(
+ private saleService: SaleService,
+ private partnerService: PartnerService,
+ private productService: ProductService,
+ private translateService: TranslateService
+ ) {
+ this.saleForm = saleForm;
+
+ this.saleSub = new Subscription();
+ }
+
+ ngOnInit(): void {
+ this.saleForm = FormGroupInitializer.initFormGroup(this.saleForm, this.sale);
+ }
+
+ protected searchPartners: OperatorFunction = (text$: Observable) =>
+ text$.pipe(
+ debounceTime(200),
+ distinctUntilChanged(),
+ filter((term) => term.length >= 2),
+ switchMap((term) => this.fetchPartners(term)),
+ map((partners) => partners.slice(0, 10)),
+ );
+
+ protected searchProducts: OperatorFunction = (text$: Observable) =>
+ text$.pipe(
+ debounceTime(200),
+ distinctUntilChanged(),
+ filter((term) => term.length >= 2),
+ switchMap((term) => this.fetchProducts(term)),
+ map((products) => products.slice(0, 10)),
+ );
+
+ protected fetchPartners(term: string): Observable<{ id: any; name: any }[]> {
+ return this.partnerService.partnersGetCollection(1, 50, undefined, undefined, term).pipe(
+ map((response) => response['hydra:member'].map(partner => ({id: partner.id, name: partner.name}))),
+ );
+ }
+
+ protected fetchProducts(term: string): Observable<{ id: any; name: any }[]> {
+ return this.productService.productsGetCollection(1, 50, term).pipe(
+ map((response) => response['hydra:member'].map(product => ({id: product.id, name: product.name}))),
+ );
+ }
+
+ protected onPartnerSelect(selectedItem: any): void {
+ this.saleForm.get('partner')?.setValue(selectedItem.item.id);
+ }
+
+ protected onProductSelect(selectedItem: any): void {
+ this.saleForm.get('product')?.setValue(selectedItem.item.id);
+ }
+
+ onSubmit() {
+ if (this.saleForm.valid) {
+ if (this.saleForm.get('profit')?.value > this.saleForm.get('turnover')?.value) {
+ let alertMessage = "";
+ this.translateService.get('system.profit-larger-turnover').subscribe((translation: string) => {
+ alertMessage = translation;
+ });
+ alert(alertMessage);
+ return;
+ }
+ if (this.sale.id === null || this.sale.id === undefined) {
+ // Create new sale
+ this.saleSub = this.saleService.salesPost(
+ this.saleForm.value as SaleJsonld
+ ).subscribe(
+ data => {
+ this.saleForm.reset();
+ this.submit.emit(ModalStatus.Submitted);
+ }
+ );
+ } else {
+ // Edit sale
+ this.saleSub = this.saleService.salesIdPatch(
+ ApiConverter.extractId(this.sale.id),
+ this.saleForm.value as SaleJsonld
+ ).subscribe(
+ data => {
+ this.saleForm.reset();
+ this.submit.emit(ModalStatus.Submitted);
+ }
+ );
+ }
+ }
+ }
+}
diff --git a/matsen-tool/src/app/sales/sales.component.ts b/matsen-tool/src/app/sales/sales.component.ts
index 5f7bd45..c085eec 100644
--- a/matsen-tool/src/app/sales/sales.component.ts
+++ b/matsen-tool/src/app/sales/sales.component.ts
@@ -19,6 +19,7 @@ import {ApiConverter} from "@app/_helpers/api.converter";
import {Router} from "@angular/router";
import {registerLocaleData} from "@angular/common";
import localeDe from '@angular/common/locales/de';
+import {NewSaleComponent} from "@app/sales/new-sale/new-sale.component";
registerLocaleData(localeDe);
@@ -163,13 +164,14 @@ export class SalesComponent implements OnInit {
}
openModalNewSale() {
- const modalRefContact = this.modalService.open(NewPartnerComponent, this.modalOptions);
+ const modalRefSale = this.modalService.open(NewSaleComponent, this.modalOptions);
let sale: SaleJsonld = {} as SaleJsonld;
- modalRefContact.componentInstance.partner = sale;
- modalRefContact.componentInstance.submit.subscribe((modalStatus: ModalStatus) => {
+ modalRefSale.componentInstance.sale = sale;
+ modalRefSale.componentInstance.submit.subscribe((modalStatus: ModalStatus) => {
if (modalStatus === ModalStatus.Submitted) {
- modalRefContact.dismiss();
+ modalRefSale.dismiss();
this.getSalesData();
+ this.getSalesSummaryData();
}
});
}
diff --git a/matsen-tool/src/assets/i18n/de.json b/matsen-tool/src/assets/i18n/de.json
index be2d8cf..31aba50 100644
--- a/matsen-tool/src/assets/i18n/de.json
+++ b/matsen-tool/src/assets/i18n/de.json
@@ -4,7 +4,8 @@
"delete-image": "Bild löschen",
"confirm-delete-image": "Möchten Sie das Bild wirklich löschen?",
"delete-file": "Datei löschen",
- "confirm-delete-file": "Möchten Sie die Datei wirklich löschen?"
+ "confirm-delete-file": "Möchten Sie die Datei wirklich löschen?",
+ "profit-larger-turnover": "Der Gewinn ist größer als der Umsatz!"
},
"basic":
{
@@ -41,6 +42,7 @@
"edit-post": "Notiz bearbeiten",
"edit-comment": "Kommentar bearbeiten",
"edit-task-note": "Anmerkung bearbeiten",
+ "edit-sale": "Verkauf bearbeiten",
"details": "Details",
"comment-it": "Kommentieren",
"show-comments": "Kommentare anzeigen",
@@ -107,6 +109,8 @@
"prio-high": "hoch",
"partner": "Partner",
"product": "Produkt",
+ "turnover": "Umsatz",
+ "profit": "Gewinn",
"send": "Abschicken"
},
"sales":