Add CargoPartner/CargoTruck entities and logistics links
Introduced CargoPartner and CargoTruck entities for logistics, updated Shipping and IShipping to link to carrier and vehicles, and enhanced UI grids for selection and validation. Updated documentation and glossary to reflect new logistics model and terminology. Removed obsolete Shippings navigation from CargoPartner.
This commit is contained in:
parent
c9b0bf8334
commit
3cb5efe2d2
|
|
@ -7,7 +7,7 @@ using Mango.Nop.Core.Entities;
|
|||
namespace FruitBank.Common.Entities;
|
||||
|
||||
[AcBinarySerializable(false, true, false, true, false, false)]
|
||||
//[ToonDescription("Business partner with address and tax information", Purpose = "Represents an external legal entity, specifically a Supplier who provides goods or a business partner involved in the procurement chain")]
|
||||
[ToonDescription("Transport / haulage company (carrier) with its vehicle fleet", Purpose = "A carrier that delivers goods to the warehouse and owns the CargoTrucks (both trucks and trailers). Distinct from Partner, which is the goods supplier. Name, address and tax fields are inherited from PartnerBase.")]
|
||||
[Table(Name = FruitBankConstClient.CargoPartnerDbTableName)]
|
||||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.CargoPartnerDbTableName)]
|
||||
public sealed class CargoPartner : PartnerBase, ICargoPartner
|
||||
|
|
@ -16,6 +16,5 @@ public sealed class CargoPartner : PartnerBase, ICargoPartner
|
|||
public List<CargoTruck>? CargoTrucks { get; set; }
|
||||
|
||||
//[Association(ThisKey = nameof(Id), OtherKey = nameof(Shipping.CargoPartnerId), CanBeNull = true)]
|
||||
public List<Shipping>? Shippings { get; set; }
|
||||
//public decimal DecProp{get; set; }
|
||||
//public List<Shipping>? Shippings { get; set; }
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -11,6 +11,11 @@ Domain entities for inbound/outbound goods tracking and inventory. All map to `f
|
|||
- **`ShippingDocumentToFiles.cs`** — Many-to-many link: document ↔ file with DocumentType. Table: `fbShippingDocumentToFiles`.
|
||||
- **`Partner.cs`** — External supplier with address and tax info. Table: `fbPartner`.
|
||||
|
||||
## Cargo / Logistics
|
||||
|
||||
- **`CargoPartner.cs`** — Freight/haulage partner (carrier). Distinct from `Partner` (supplier) — this is the transport side. Has `CargoTrucks` and `Shippings` collections. Table: `fbCargoPartner`.
|
||||
- **`CargoTruck.cs`** — Individual truck belonging to a `CargoPartner` (`LicencePlate`, `CountryCode`, `IsTrailer` for trailers). Table: `fbCargoTruck`.
|
||||
|
||||
## Order (Outbound)
|
||||
|
||||
- **`OrderItemPallet.cs`** — Measurement record for outgoing goods with RevisorId for audit. Table: `fbOrderItemPallet`.
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ namespace FruitBank.Common.Entities;
|
|||
[System.ComponentModel.DataAnnotations.Schema.Table(FruitBankConstClient.ShippingDbTableName)]
|
||||
public sealed class Shipping : MgEntityBase, IShipping, IEntityComment
|
||||
{
|
||||
public int CargoPartnerId { get; set; }
|
||||
public int? CargoTruckId { get; set; }
|
||||
public int? CargoTrailerId { get; set; }
|
||||
|
||||
public DateTime ShippingDate { get; set; } = DateTime.Now;
|
||||
public string LicencePlate { get; set; }
|
||||
public bool IsAllMeasured { get; set; }
|
||||
|
|
@ -21,6 +25,18 @@ public sealed class Shipping : MgEntityBase, IShipping, IEntityComment
|
|||
|
||||
public DateTime? MeasuredDate { get; set; }
|
||||
|
||||
[ToonDescription(Purpose = "The transport company (carrier) that hauled this delivery — distinct from the goods supplier, which is reached via ShippingDocument.Partner.")]
|
||||
[Association(ThisKey = nameof(CargoPartnerId), OtherKey = nameof(CargoPartner.Id), CanBeNull = true)]
|
||||
public CargoPartner CargoPartner { get; set; }
|
||||
|
||||
[ToonDescription(Purpose = "The tractor/truck unit — a CargoTruck row with IsTrailer=false.")]
|
||||
[Association(ThisKey = nameof(CargoTruckId), OtherKey = nameof(CargoTruck.Id), CanBeNull = true)]
|
||||
public CargoTruck CargoTruck { get; set; }
|
||||
|
||||
[ToonDescription(Purpose = "The trailer — the SAME CargoTruck table as CargoTruck, but the row with IsTrailer=true (CargoTrailerId → CargoTruck.Id).")]
|
||||
[Association(ThisKey = nameof(CargoTrailerId), OtherKey = nameof(CargoTruck.Id), CanBeNull = true)]
|
||||
public CargoTruck CargoTrailer { get; set; }
|
||||
|
||||
[Association(ThisKey = nameof(Id), OtherKey = nameof(ShippingDocument.ShippingId), CanBeNull = true)]
|
||||
public List<ShippingDocument>? ShippingDocuments { get; set; }
|
||||
|
||||
|
|
|
|||
|
|
@ -14,4 +14,6 @@ public interface ICargoTruck : IEntityInt, ITimeStampInfo
|
|||
public string LicencePlate { get; set; }
|
||||
|
||||
public bool IsTrailer { get; set; }
|
||||
|
||||
public string? CargoPartnerName { get; }
|
||||
}
|
||||
|
|
@ -6,6 +6,10 @@ namespace FruitBank.Common.Interfaces;
|
|||
|
||||
public interface IShipping : IEntityInt, ITimeStampInfo//, IMeasured
|
||||
{
|
||||
public int CargoPartnerId { get; set; }
|
||||
public int? CargoTruckId { get; set; }
|
||||
public int? CargoTrailerId { get; set; }
|
||||
|
||||
DateTime ShippingDate { get; set; }
|
||||
string LicencePlate { get; set; }
|
||||
bool IsAllMeasured { get; set; }
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@
|
|||
@if (IsMasterGrid)
|
||||
{
|
||||
var cargoPartner = ((CargoPartner)context.DataItem);
|
||||
var shippings = cargoPartner?.Shippings ?? [];
|
||||
var shippings = new AcObservableCollection<Shipping>(); //cargoPartner?.Shippings ?? [];
|
||||
var cargoTrucks = cargoPartner?.CargoTrucks ?? [];
|
||||
|
||||
<DxTabs>
|
||||
|
|
@ -56,13 +56,13 @@
|
|||
}
|
||||
</DxTabPage>
|
||||
|
||||
<DxTabPage Text="Szállítmányok">
|
||||
@* <DxTabPage Text="Szállítmányok">
|
||||
@{
|
||||
var observableShippings = new AcObservableCollection<Shipping>(shippings);
|
||||
<GridShipping Shippings="@observableShippings" IsMasterGrid="false" />
|
||||
//var observableShippings = new AcObservableCollection<Shipping>(shippings);
|
||||
<GridShipping Shippings="@shippings" IsMasterGrid="false" />
|
||||
}
|
||||
</DxTabPage>
|
||||
</DxTabs>
|
||||
*@ </DxTabs>
|
||||
}
|
||||
</DetailRowTemplate>
|
||||
<ToolbarTemplate>
|
||||
|
|
@ -83,6 +83,7 @@
|
|||
[Parameter] public AcObservableCollection<CargoPartner>? CargoPartners { get; set; }
|
||||
[Parameter] public AcObservableCollection<Shipping>? Shippings { get; set; }
|
||||
|
||||
|
||||
const string ExportFileName = "ExportResult";
|
||||
string GridSearchText = "";
|
||||
bool EditItemsEnabled { get; set; }
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
@using FruitBank.Common.Entities
|
||||
@using FruitBankHybrid.Shared.Components.Grids.Shippings
|
||||
@using FruitBankHybrid.Shared.Databases
|
||||
@using FruitBankHybrid.Shared.Extensions
|
||||
@using FruitBankHybrid.Shared.Services.Loggers
|
||||
@using FruitBankHybrid.Shared.Services.SignalRs
|
||||
|
||||
|
|
@ -19,11 +20,68 @@
|
|||
<GridContent>
|
||||
<GridShippingBase @ref="Grid" DataSource="Shippings" AutoSaveLayoutName="GridShipping" SignalRClient="FruitBankSignalRClient" Logger="_logger"
|
||||
CssClass="@GridCss" ValidationEnabled="false"
|
||||
OnGridEditModelSaving="Grid_EditModelSaving"
|
||||
OnGridFocusedRowChanged="Grid_FocusedRowChanged">
|
||||
<Columns>
|
||||
<DxGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Descending" ReadOnly="true" />
|
||||
|
||||
<DxGridDataColumn FieldName="ShippingDate" Caption="Beérkezés" />
|
||||
<DxGridDataColumn FieldName="CargoPartnerId" Caption="Fuvarozó">
|
||||
<EditSettings>
|
||||
<DxComboBoxSettings Data="CargoPartners"
|
||||
ValueFieldName="Id"
|
||||
TextFieldName="Name"
|
||||
DropDownBodyCssClass="dd-body-class"
|
||||
ListRenderMode="ListRenderMode.Entire"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto">
|
||||
<Columns>
|
||||
<DxListEditorColumn FieldName="@nameof(CargoPartner.Id)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoPartner.Name)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoPartner.TaxId)" />
|
||||
</Columns>
|
||||
</DxComboBoxSettings>
|
||||
</EditSettings>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="CargoTruckId" Caption="Vontató">
|
||||
<EditSettings>
|
||||
<DxComboBoxSettings Data="CargoTrucks.Where(x => !x.IsTrailer)"
|
||||
ValueFieldName="Id"
|
||||
TextFieldName="LicencePlate"
|
||||
DropDownBodyCssClass="dd-body-class"
|
||||
ListRenderMode="ListRenderMode.Entire"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto">
|
||||
<Columns>
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.Id)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.CargoPartnerName)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.LicencePlate)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.IsTrailer)" />
|
||||
</Columns>
|
||||
</DxComboBoxSettings>
|
||||
</EditSettings>
|
||||
</DxGridDataColumn>
|
||||
<DxGridDataColumn FieldName="CargoTrailerId" Caption="Utánfutó">
|
||||
<EditSettings>
|
||||
<DxComboBoxSettings Data="CargoTrucks.Where(x => x.IsTrailer)"
|
||||
ValueFieldName="Id"
|
||||
TextFieldName="LicencePlate"
|
||||
DropDownBodyCssClass="dd-body-class"
|
||||
ListRenderMode="ListRenderMode.Entire"
|
||||
SearchMode="ListSearchMode.AutoSearch"
|
||||
SearchFilterCondition="ListSearchFilterCondition.Contains"
|
||||
ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto">
|
||||
<Columns>
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.Id)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.CargoPartnerName)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.LicencePlate)" />
|
||||
<DxListEditorColumn FieldName="@nameof(CargoTruck.IsTrailer)" />
|
||||
</Columns>
|
||||
</DxComboBoxSettings>
|
||||
</EditSettings>
|
||||
</DxGridDataColumn>
|
||||
|
||||
<DxGridDataColumn FieldName="LicencePlate" Caption="Rendszám" />
|
||||
<DxGridDataColumn FieldName="Comment" Caption="Megjegyzés" ReadOnly="false" />
|
||||
<DxGridDataColumn FieldName="CargoCompany" Caption="Fuvarozó" ReadOnly="false" />
|
||||
|
|
@ -71,7 +129,11 @@
|
|||
|
||||
[Parameter] public bool IsMasterGrid { get; set; } = false;
|
||||
[Parameter] public AcObservableCollection<Partner>? Partners { get; set; }
|
||||
[Parameter] public AcObservableCollection<CargoPartner>? CargoPartners { get; set; }
|
||||
[Parameter] public AcObservableCollection<Shipping>? Shippings { get; set; }
|
||||
[Inject] public required IDialogService DialogService { get; set; } = null!;
|
||||
|
||||
public List<CargoTruck> CargoTrucks { get; set; } = [];
|
||||
|
||||
const string ExportFileName = "ExportResult";
|
||||
string GridSearchText = "";
|
||||
|
|
@ -91,6 +153,23 @@
|
|||
|
||||
private async Task ReloadDataFromDb(bool forceReload = false)
|
||||
{
|
||||
using (await ObjectLock.GetSemaphore<CargoPartner>().UseWaitAsync())
|
||||
{
|
||||
if (CargoPartners == null) CargoPartners = new AcObservableCollection<CargoPartner>(await FruitBankSignalRClient.GetCargoPartners() ?? []);
|
||||
else if (CargoPartners.Count == 0 || forceReload)
|
||||
{
|
||||
CargoPartners.Replace(await FruitBankSignalRClient.GetCargoPartners() ?? []);
|
||||
}
|
||||
}
|
||||
|
||||
CargoTrucks = CargoPartners.Where(x => x.CargoTrucks != null).SelectMany(x =>
|
||||
{
|
||||
if (x.CargoTrucks == null) return null;
|
||||
|
||||
foreach (var cargoTruck in x.CargoTrucks) cargoTruck.CargoPartner = x;
|
||||
return x.CargoTrucks;
|
||||
}).ToList();
|
||||
|
||||
if (!IsMasterGrid) return;
|
||||
|
||||
using (await ObjectLock.GetSemaphore<Partner>().UseWaitAsync())
|
||||
|
|
@ -121,7 +200,23 @@
|
|||
EditItemsEnabled = true;
|
||||
}
|
||||
|
||||
protected async Task OnActiveTabChanged(int activeTabIndex)
|
||||
async Task Grid_EditModelSaving(GridEditModelSavingEventArgs e)
|
||||
{
|
||||
var shipping = (Shipping)e.EditModel; // a szerkesztett sor
|
||||
|
||||
if (ValidateCargoConsistency(shipping, out string error)) return;
|
||||
|
||||
e.Cancel = true;
|
||||
await DialogService.ShowMessageBoxAsync("Hibás adat", error, MessageBoxRenderStyle.Danger);
|
||||
// e.IsNew → add vs update
|
||||
|
||||
// ... before-save logika (validáció, számított mezők, CargoTrailer beállítás stb.)
|
||||
|
||||
// megszakítás, ha kell:
|
||||
// e.Cancel = true;
|
||||
}
|
||||
|
||||
async protected Task OnActiveTabChanged(int activeTabIndex)
|
||||
{
|
||||
_activeTabIndex = activeTabIndex;
|
||||
return;
|
||||
|
|
@ -142,5 +237,29 @@
|
|||
// break;
|
||||
// }
|
||||
}
|
||||
|
||||
private bool ValidateCargoConsistency(Shipping shipping, out string? error)
|
||||
{
|
||||
error = null;
|
||||
|
||||
if (shipping.CargoTruckId != null)
|
||||
{
|
||||
var truck = CargoTrucks.FirstOrDefault(t => t.Id == shipping.CargoTruckId);
|
||||
if (truck == null || truck.CargoPartnerId != shipping.CargoPartnerId)
|
||||
{
|
||||
error = $"A vontató ({truck?.LicencePlate}) nem a kiválasztott fuvarozóhoz tartozik!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (shipping.CargoTrailerId == null) return true;
|
||||
|
||||
var trailer = CargoTrucks.FirstOrDefault(t => t.Id == shipping.CargoTrailerId);
|
||||
if (trailer != null && trailer.CargoPartnerId == shipping.CargoPartnerId) return true;
|
||||
|
||||
error = $"Az utánfutó ({trailer?.LicencePlate}) nem a kiválasztott fuvarozóhoz tartozik!";
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ Domain terminology for the FruitBank system. **Read this before making changes.*
|
|||
| **Order** | Megrendelés | **OUTBOUND** delivery: warehouse → customer. |
|
||||
| **Pallet** (XxxItemPallet) | Mérési rekord | A **measurement record**, NOT a physical pallet. Always created, even for non-measurable products. |
|
||||
| **Partner** | Partner / Beszállító | External supplier providing goods. |
|
||||
| **CargoPartner** | Fuvarozó | Freight carrier company that transports goods. **Distinct from Partner** (supplier). |
|
||||
| **CargoTruck** | Kamion | A specific truck belonging to a CargoPartner (licence plate, trailer flag). |
|
||||
| **ShippingDocument** | Szállítólevél | Supplier's delivery note or invoice, linked to a Shipping. |
|
||||
| **ShippingItem** | Szállítólevél tétel | Product line on a shipping document. Tracks declared vs measured discrepancies. |
|
||||
| **StockTaking** | Leltározás | Inventory session that freezes logical stock and reconciles with physical count. |
|
||||
|
|
|
|||
Loading…
Reference in New Issue