Codebasis als Dateien ins Arbeitsrepo statt als Gitlink

QuellCode/CentronERP war nur als Gitlink (Submodul-Referenz auf 79c1142)
getrackt, ohne .gitmodules und ohne erreichbares Remote. Der
Untersuchungsgegenstand der Versuchsreihe war damit nicht reproduzierbar
gesichert: Ein Klon haette ein leeres Verzeichnis erhalten, und die Belege
der 3.287 Anforderungen waeren nicht ueberpruefbar gewesen.

Umstellung:
- Historie nach c:\DEV\CentronERP_git_snapshot_79c1142 ausgelagert
  (vollstaendig lesbar, enthaelt 79c1142 und Vorgaenger 89ccfd6)
- Gitlink aus dem Index entfernt
- Dateiinhalt aufgenommen: 24.557 Dateien, rund 333 MB

Die verschachtelte .gitignore der Codebasis gilt weiter, Build-Artefakte
bleiben ausgeschlossen. Details in Versuche/Versuch_01/_Codebasis-Nachweis.md
This commit is contained in:
Christoph Schwörer
2026-08-26 07:43:51 +02:00
parent 18edae75b6
commit f045b99a25
24664 changed files with 5846716 additions and 1 deletions
@@ -0,0 +1,123 @@
# RMM-Article Logic in Contract Billing
## Overview
The Remote Monitoring Management (RMM) Article functionality in c-entron.NET allows for automatic billing of usage-based services that are measured by an external RMM system. This document outlines the rules, workflow, and technical implementation of the RMM Article billing process.
## Key Concepts
### RMM System Integration
- The c-entron.NET application integrates with external RMM systems (e.g., "Riverbird") to retrieve usage statistics
- Usage data is collected for specified periods and used to calculate billing amounts
- Communication happens via the `RiverConnectionBL` class which connects to the RMM service
### Contract Article References
- Each billable RMM item is defined as a `ContractArticleReferenzes` entity
- These references link articles in c-entron.NET to specific metrics in the RMM system
- Article references contain configuration for billing calculation rules
## Workflow
### 1. Contract Configuration
1. A contract is configured to use RMM billing (`WhetherRMM` returns true)
2. Contract article references are configured, specifying:
- Article type (e.g., server, workstation)
- Article reference (linking to the inventory item)
- Pricing rules
### 2. Invoice Generation Process
1. During the `CreateInvoiceToContractComplete` process, `CheckRMMArticle` is called
2. The system checks if the contract has RMM enabled
3. The system looks for a placeholder tag `@@RMMArtikel@@` in the invoice template
4. Contract article references are retrieved for the specific contract
5. The system queries the external RMM service for usage data in the billing period
6. For each article reference with available usage data:
- Usage amount is calculated using `CalculateContractBillingAmount`
- An invoice line item is created with the calculated amount
- Descriptive text is added explaining the service type
- The item is inserted at the position marked by `@@RMMArtikel@@` or near the end of the invoice
### 3. Placeholder Handling
- If the invoice template contains a text element with `@@RMMArtikel@@`, it serves as a position marker
- This placeholder is removed and replaced with the actual RMM article items
- If no placeholder is found, RMM items are inserted near the end of the invoice (count - 2 position)
## Error Handling
### External Service Unavailability
- If the RMM service is unavailable during invoice generation, and the contract requires RMM data:
- An `RMMServiceUnavailableException` is thrown
- The invoice creation process is aborted
- An error message is logged with details about the failure
- This prevents invoices from being created with incomplete usage data, ensuring customers are billed correctly
### Data Integrity Rules
- When a parent entity is deleted (State = 0), related child entities should also be marked as deleted
- This ensures data consistency when RMM configurations change
## Technical Implementation Details
### RMM Article Detection
```csharp
var rmmItem = invoice.Items.FirstOrDefault(f =>
(f.RichText != null && f.RichText.IndexOf("@@RMMArtikel@@", StringComparison.InvariantCulture) > -1) ||
(f.Text != null && f.Text.IndexOf("@@RMMArtikel@@", StringComparison.InvariantCulture) > -1));
```
### Usage Data Retrieval
```csharp
var riverbirdStatisticsResult = new RiverConnectionBL(this.Session).GetContractBillingAmounts(
billingParam.InvoiceFrom.Value,
billingParam.InvoiceTo.Value.AddDays(1),
invoice.CustomerI3D,
rmmArticleReferences);
```
### Error Handling for Service Unavailability
```csharp
if (riverbirdStatisticsResult.Status is ResultStatus.Error)
{
// Only throw exception when RMM articles are expected
if (rmmItem != null || rmmArticleReferences.Any())
{
string errorMsg = $"Die Rechnung kann nicht erstellt werden, da der RMM-Service nicht erreichbar ist. " +
$"Fehlermeldung: {riverbirdStatisticsResult.Message}";
_logger.Error(errorMsg);
throw new RMMServiceUnavailableException(errorMsg);
}
return;
}
```
## Best Practices
1. **Service Configuration**
- Ensure the RMM service URL is properly configured in application settings
- Verify authentication tickets are valid for the RMM service
2. **Contract Setup**
- Associate correct article references with appropriate RMM metrics
- Set proper calculation rules for each article type
3. **Invoice Templates**
- Include the `@@RMMArtikel@@` placeholder in invoice templates where RMM items should appear
- Ensure proper formatting and positioning for RMM article items
4. **Monitoring**
- Monitor logs for RMM service connectivity issues
- Periodically verify that usage data is being correctly retrieved and calculated
## Troubleshooting
| Problem | Possible Cause | Solution |
|---------|---------------|----------|
| No RMM items in invoice | RMM not enabled for contract | Check contract configuration |
| No RMM items in invoice | No usage data in RMM system | Verify usage data in RMM system |
| Invoice creation fails | RMM service unavailable | Check network connectivity and service status |
| Incorrect billing amounts | Calculation rules misconfigured | Review article reference configuration |
## Related Components
- `AutomaticFacturaWebServiceBL` - Main billing logic
- `RiverConnectionBL` - Handles communication with RMM service
- `ContractArticleReferenzes` - Defines article references for RMM billing
@@ -0,0 +1,398 @@
# ActionPrice System Documentation
## Overview
The ActionPrice (Aktionspreis) system in c-entron manages time-limited promotional pricing from distributors and manufacturers. It integrates seamlessly with the price matrix (Preismatrix) to provide users with current action prices alongside other pricing sources.
## Table of Contents
- [Database Structure](#database-structure)
- [Architecture & Components](#architecture--components)
- [Data Flow](#data-flow)
- [Data Sources](#data-sources)
- [UI Access](#ui-access)
- [Integration with Price Matrix](#integration-with-price-matrix)
- [API Reference](#api-reference)
- [Business Rules](#business-rules)
## Database Structure
### Table: `HerstellerArtikAktionspreis`
**Location**: SQL Server database
**Mapped by**: `ActionPriceMaps.cs`
| Column | Data Type | Description |
|--------|-----------|-------------|
| `I3D` | int IDENTITY(1,1) | Primary key |
| `ArtikelI3D` | int | Foreign key to Article table |
| `Artikelcode` | nvarchar(60) | Article code |
| `Preis` | decimal | Action price |
| `Distributor` | nvarchar(100) | Distributor name |
| `GueltigAb` | datetime2(2) | Effective from date |
| `GueltigBis` | datetime2(2) | Effective until date |
| `Text` | nvarchar(500) | Description/notes |
| `Hersteller` | nvarchar(60) | Manufacturer |
| `BearbeiterI3D` | int | Editor user ID |
| `EDI_I3D` | int | EDI integration ID (reserved) |
| `Verfuegbarkeit` | nvarchar(50) | Availability |
| `VK` | decimal | Selling price |
| `Kreditorcode` | nvarchar(50) | Creditor code |
| `Status` | int | Status flag |
| `DistID` | nvarchar(50) | Distributor product ID |
## Architecture & Components
### Core Components
#### 1. Entity Layer
- **File**: `Centron.Entities/Warehousing/ActionPrice.cs`
- **Purpose**: Domain entity representing action price data
- **Properties**: Maps 1:1 with database columns
#### 2. Data Access Layer (DAO)
- **File**: `Centron.DAO/Mappings/Warehousing/ActionPriceMaps.cs`
- **Purpose**: NHibernate mapping for ActionPrice entity
- **Technology**: FluentNHibernate
#### 3. Business Logic Layer (BL)
- **File**: `Centron.BL/Warehousing/ActionPriceBL.cs`
- **Methods**:
- `GetActionPrice(int actionPriceI3D)`
- `GetActionPricesByArticleI3D(int articleI3D)`
- `SaveOrUpdateActionPrice(ActionPrice actionPrice)`
- `DeleteActionPrice(ActionPrice actionPrice)`
#### 4. Web Service Layer
- **File**: `Centron.BL/WebServices/Warehousing/ActionPriceWebServiceBL.cs`
- **Purpose**: DTO conversion and web service operations
- **Features**: Entity ↔ DTO mapping using ObjectMapper
#### 5. REST API
- **File**: `CentronRestService.cs`
- **Endpoints**:
- `POST /GetActionPrice`
- `POST /GetActionPricesByArticleI3D`
- `POST /SaveOrUpdateActionPrice`
- `POST /DeleteActionPrice`
### Dual Implementation Pattern
Following c-entron's standard pattern, ActionPrice supports both connection types:
#### BL Logic (Direct Database)
- **File**: `BLActionPriceLogic.cs`
- **Connection**: `CentronConnectionType.SqlServer`
- **Access**: Direct database via NHibernate
#### WS Logic (Web Service)
- **File**: `WSActionPriceLogic.cs`
- **Connection**: `CentronConnectionType.CentronWebServices`
- **Access**: REST API calls
## Data Flow
### Reading ActionPrices
```
1. Price Matrix Request
↓
2. Article Lookup (by ManufacturerCode or EAN)
↓
3. IActionPriceLogic.GetActionPricesByArticleI3D()
↓
4. Filter by Date Range (current valid prices only)
↓
5. Convert to PriceItemViewModel
↓
6. Display in Price Matrix Grid
```
### Creating ActionPrices
```
1. User Right-clicks Price Matrix Grid
↓
2. Select "Aktionspreis hinzufügen"
↓
3. AddActionPriceViewModel Dialog Opens
↓
4. User Enters Data (Distributor, Price, Dates)
↓
5. Validation (Distributor required, valid date range)
↓
6. IActionPriceLogic.SaveOrUpdateActionPrice()
↓
7. Data Saved to Database
↓
8. Price Matrix Refreshed
```
## Data Sources
### Current Active Sources
#### 1. Manual Entry (Primary)
- **Location**: Article Management → Additional Info → Preisspiegel Tab
- **Method**: Right-click context menu → "Aktionspreis hinzufügen"
- **Validation**:
- Distributor name required
- EffectiveFrom ≤ EffectiveUntil
- **User Tracking**: EditorI3D field tracks creator
### Potential Sources (Infrastructure Exists)
#### 1. EDI Integration
- **Evidence**: `EDI_I3D` field in database
- **Status**: Infrastructure exists but no active implementation found
- **Purpose**: Automated import from supplier EDI systems
#### 2. Bulk Import
- **Evidence**: Standard c-entron import patterns
- **Status**: No specific ActionPrice import modules identified
- **Potential**: Could be implemented for supplier data feeds
## UI Access
### Step-by-Step Navigation
1. **Open Article Management**
- Navigate: Warehousing → Article Management
2. **Select Article**
- Search for and open an existing article
3. **Access Additional Info**
- Navigate to "Zusatzinfo" (Additional Info) section
4. **Open Preisspiegel Tab**
- Click on "Preisspiegel" tab
- This displays the price matrix grid
5. **Access ActionPrice Functions**
- **Right-click** on the price matrix grid
- Context menu appears with options:
- "Preisspiegel aktualisieren" (Refresh)
- "Aktionspreis hinzufügen" (Add ActionPrice)
- "Aktionspreis bearbeiten" (Edit ActionPrice)
- "Aktionspreis löschen" (Delete ActionPrice)
### UI Components
- **View**: `ArticleAdditionalInfoView.xaml`
- **ViewModel**: `ArticleAdditionalInfoViewModel.cs`
- **Grid**: `PriceWatchGridControl` (line 68)
- **Tab**: "Preisspiegel" (line 64)
- **Context Menu**: Lines 123-141
## Integration with Price Matrix
### Price Matrix Sources
ActionPrice is one of 7 parallel price sources in the matrix:
1. **ITscope** - External API
2. **Article Import** - Imported price data
3. **COP** - External API
4. **NEOS** - External API
5. **TradersGuide** - External API
6. **EGIS** - External API
7. **Aktionspreise** - Internal action prices ←
### Display Logic
- **File**: `PriceMatrixViewModel.cs`
- **Method**: `GetPriceItemsFromArticleActionPrices()` (lines 416-459)
- **Filtering**: Only shows prices where current date is within EffectiveFrom/EffectiveUntil range
- **Service Label**: Displays as "Aktionspreise" in Service column
- **Description Format**: "Aktionspreis vom {EffectiveFrom:d} bis {EffectiveUntil:d}. {Text}"
### Price Item Properties
```csharp
// ActionPrice in Price Matrix
Service = "Aktionspreise"
Supplier = actionPrice.Distributor
PurchasePrice = actionPrice.Price
RawPurchasePrice = actionPrice.Price
Date = actionPrice.EffectiveFrom
Stock = null // Always visible
ArticleDescription = "Aktionspreis vom ... bis ... {Text}"
```
## API Reference
### REST Endpoints
#### Get Single ActionPrice
```http
POST /GetActionPrice
Content-Type: application/json
{
"Data": 123 // ActionPrice I3D
}
```
#### Get ActionPrices by Article
```http
POST /GetActionPricesByArticleI3D
Content-Type: application/json
{
"Data": 456 // Article I3D
}
```
#### Save or Update ActionPrice
```http
POST /SaveOrUpdateActionPrice
Content-Type: application/json
{
"Data": {
"I3D": 0, // 0 for new, >0 for update
"ArticleI3D": 456,
"ArticleCode": "ART001",
"Price": 99.99,
"Distributor": "Supplier Name",
"EffectiveFrom": "2024-01-01T00:00:00",
"EffectiveUntil": "2024-12-31T23:59:59",
"Text": "Special promotion",
"Manufacturer": "Brand Name"
}
}
```
#### Delete ActionPrice
```http
POST /DeleteActionPrice
Content-Type: application/json
{
"Data": {
"I3D": 123,
// ... other properties
}
}
```
### Code Usage
#### Get ActionPrices for Article
```csharp
var actionPrices = await ClassContainer.Instance
.WithInstance((IActionPriceLogic logic) =>
logic.GetActionPricesByArticleI3D(articleI3D))
.ThrowIfError();
```
#### Save New ActionPrice
```csharp
var actionPriceDTO = new ActionPriceDTO
{
ArticleI3D = articleI3D,
Distributor = "Supplier Name",
Price = 99.99,
EffectiveFrom = DateTime.Now,
EffectiveUntil = DateTime.Now.AddMonths(3),
Text = "Special promotion"
};
await ClassContainer.Instance
.WithInstance((IActionPriceLogic logic) =>
logic.SaveOrUpdateActionPrice(actionPriceDTO))
.ThrowIfError();
```
## Business Rules
### Validation Rules
1. **Required Fields**
- `Distributor` - Must not be empty or whitespace
2. **Date Validation**
- `EffectiveFrom` must be ≤ `EffectiveUntil`
- Both dates are required
3. **Display Rules**
- Only ActionPrices with current date within effective range show in Price Matrix
- Filter: `EffectiveFrom.StartOfDay() <= DateTime.Now && EffectiveUntil >= DateTime.Now`
### Data Integrity
1. **Article Linking**
- ActionPrices are linked to articles via `ArticleI3D`
- Article must exist in system
2. **User Tracking**
- `EditorI3D` tracks who created/modified the record
- Automatically set during save operations
3. **Status Management**
- `Status` field available for workflow management
- Currently not actively used in UI
### Price Matrix Integration
1. **Loading Priority**
- ActionPrices loaded in parallel with other price sources
- No specific priority ordering
2. **Cache Behavior**
- Price matrix results are cached by ManufacturerCode + EANCode
- Cache invalidated when ActionPrices are modified
3. **Display Formatting**
- ActionPrices always show Stock as null (always visible)
- Service column shows "Aktionspreise"
- Description includes date range and text
## Troubleshooting
### Common Issues
1. **ActionPrice Not Visible in Price Matrix**
- Check if current date is within EffectiveFrom/EffectiveUntil range
- Verify article linking via ArticleI3D
- Ensure Price Matrix cache is refreshed
2. **Context Menu Not Appearing**
- Ensure right-clicking directly on the Price Matrix grid
- Check if article is properly selected
- Verify user is in "Preisspiegel" tab
3. **Save Validation Errors**
- Verify Distributor field is not empty
- Check date range: EffectiveFrom ≤ EffectiveUntil
- Ensure all required fields are populated
### Debug Information
- **Price Matrix Loading**: Check `PriceMatrixViewModel.GetPriceItemsFromArticleActionPrices()`
- **Article Lookup**: Verify article found by ManufacturerCode or EANCode
- **Date Filtering**: Current ActionPrice validation logic
- **UI Binding**: Check `ArticleAdditionalInfoViewModel.ActionPrices` collection
## Development Notes
### Future Enhancements
1. **EDI Integration**
- `EDI_I3D` field suggests planned EDI integration
- Could automate ActionPrice imports from suppliers
2. **Bulk Import**
- Standard c-entron import patterns could be applied
- Excel/CSV import functionality possible
3. **Workflow Management**
- `Status` field could support approval workflows
- Multi-step ActionPrice approval process
4. **Advanced Filtering**
- Additional filter options in Price Matrix
- ActionPrice-specific search capabilities
### Code Maintenance
- **Entity Changes**: Update both `ActionPrice` entity and `ActionPriceDTO`
- **Database Changes**: Update `ActionPriceMaps` NHibernate mapping
- **API Changes**: Update both BL and WS logic implementations
- **UI Changes**: Update both View and ViewModel files
---
*This documentation covers the complete ActionPrice system as implemented in c-entron. For questions or updates, refer to the source code files referenced throughout this document.*
@@ -0,0 +1,435 @@
# Contracts Backend Architecture
This document describes the specific backend implementation for contracts within the c-entron.NET receipts system. Contracts extend the generic receipt architecture with specialized functionality for recurring billing, service agreements, and customer asset management.
## Overview
Contracts in c-entron.NET are specialized receipts that handle ongoing service agreements, maintenance contracts, and recurring billing scenarios. They extend the base receipt functionality with contract-specific features like billing intervals, contingent management, device tracking, and automated invoice generation.
## Entity Architecture
### ReceiptContract Entity
**Location:** `src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs`
The `ReceiptContract` class extends `ReceiptBase` and implements `IReceiptContract`. It represents the main contract entity with comprehensive contract-specific properties.
#### Core Contract Properties
**Customer and Project Information:**
- `CustomerI3D`: Primary customer reference
- `ProjectNumber`: Project identifier for the contract
- `PurchaseOrderNumber`: Customer's purchase order reference
- `AdditionalText`: Supplementary contract description
**Personnel Assignment:**
- `SalesRepresentativeI3D`: Assigned sales representative
- `OfficeStaffI3D`: Internal staff responsible for contract management
**Delivery and Billing Addresses:**
- `DeliveryAddress`, `DeliveryAddressCustomerI3D`: Service delivery location
- `InvoiceAddress`, `InvoiceAddressCustomerI3D`: Billing address information
- `LicenseeAddress`, `LicenseeAddressCustomerI3D`: Software licensing address
**Contract Lifecycle:**
- `DeliveryDate`: Contract start or service delivery date
- `ContractEnd`: Contract termination date
- `ContractTermination`: Actual termination date
- `FirstPaidDate`: Date of first payment received
- `ReminderDate`: Follow-up reminder date
- `PreparationDate`: Contract preparation date
- `FinishDate`: Contract completion date
#### Billing Configuration
**Billing Intervals:**
- `BillingIntervalKind`: Type of billing cycle (Daily, Monthly, Quarterly, Yearly)
- `BillingIntervalDuration`: Number of intervals (e.g., 3 for quarterly when kind is Monthly)
- `BillingKind`: Billing methodology (enum BillingKinds)
- `AutomatedBilling`: Boolean flag for automatic invoice generation
**Contract Calculation:**
- `CalculationKind`: How contract values are calculated (enum ContractCalculationKind)
- `CalcNeedKind`: Calculation requirements (enum ContractNeedCalcKind)
- `IsNormalize`: Whether to normalize billing amounts
- `IsFullNormalizeAmount`: Full normalization flag
**Payment and Collection:**
- `PaymentConditionI3D`: Reference to payment terms
- `PaymentConditionText`: Custom payment terms description
- `CollectInvoice`: Collection settings
- `MandatI3D`: SEPA mandate reference
#### Advanced Contract Features
**Contingent Management:**
- `ContingentUsedHours`: Hours consumed from contract contingent
- `ContingentUsedAmount`: Monetary amount consumed
- `ContingentBalanceUsedHours`: Balance hours utilized
- `ContingentBalanceUsedAmount`: Balance amount utilized
- `ContingentBalanceArticleI3D`: Article used for contingent balancing
- `UseContingentBalanceArticle`: Flag to enable balance article usage
- `ContingentResidualValueStart`: Starting residual value
- `ContingentResidualValueStartDate`: Start date for residual calculation
**Contingent Limits and Monitoring:**
- `IsContingentLimitBilling`: Enable contingent limit billing
- `ContingentLimitValue`: Limit threshold value
- `ContingentLimitKind`: Type of limit (enum ContingentLimitKinds)
- `IsMonitoring`: Enable contract monitoring
- `MonitoringValue`: Monitoring threshold
**Device and Asset Management:**
- Contract-specific device relationships through master data lists
- Serial number tracking and device lifecycle management
- Click counter management for printer/copier contracts
#### Contract Automation
**Prolongation and Renewals:**
- `AutomatedProlongation`: Automatic contract renewal flag
- `LastSubsequentBillingDate`: Date of last follow-up billing
**Web Integration:**
- `IsDisplayedOnWeb`: Web portal visibility flag
- `WebReportI3D`: Associated web report
### Database Schema
#### Contract Database Architecture
Contracts follow the dual-layer database architecture used throughout the receipts system, consisting of legacy German-named tables and modern English-named views.
#### Legacy Contract Tables
##### VertragKopf Table (Contract Headers)
**Physical Table:** `dbo.VertragKopf`
**Entity Class:** `Centron.DAO.TemporaryEntities.VertragKopf`
**Mapping:** `Centron.DAO.Mappings.TemporaryEntities.VertragKopfMaps`
The `VertragKopf` table inherits from `ReceiptTable` and contains contract header information.
**Key Columns:**
- `I3D` - Primary key (identity)
- `Nummer` - Contract number
- `KundenI3D` - Customer reference
- `Datum` - Contract date
- `Status` - Contract state
- `Berechnungsart` - Calculation method
- `AutoVerlaengerung` - Auto-renewal flag
- `AbrechnungsIntervallArt` - Billing interval type
- `AbrechnungsIntervallDauer` - Billing interval duration
- `VertragsBeginn` - Contract start date
- `VertragsEnde` - Contract end date
- `KuendigungsDatum` - Termination date
- `ErsteBezahlung` - First payment date
- `KontingentWert` - Contingent value
- `KontingentArt` - Contingent type
- `Automatische Abrechnung` - Automated billing flag
##### VertragPos Table (Contract Items)
**Physical Table:** `dbo.VertragPos`
**Entity Class:** `Centron.DAO.TemporaryEntities.VertragPos`
**Mapping:** `Centron.DAO.Mappings.TemporaryEntities.VertragPosMaps`
The `VertragPos` table contains contract line items and positions.
**Key Columns:**
- `I3D` - Primary key (identity)
- `VertragKopfI3D` - Foreign key to contract header
- `Pos` - Position number for ordering
- `ArtikelI3D` - Article/product reference
- `Text` - Item description
- `Stk` - Quantity
- `VKKalk` - Sales price calculation
- `EK` - Purchase price
- `MwstI3D` - VAT rate reference
- `VertragI3D` - Contract reference for recurring items
- `Lieferdatum` - Delivery date
- `Benachrichtigungsdatum` - Notification date
##### Contract Version Tables
**Version History Tables:**
- `VertragKopfVersions` - Contract header version history
- `VertragPosVersions` - Contract items version history
**Critical Architecture Detail:** Version tables are **exact 1:1 copies** of their corresponding original tables (`VertragKopf` and `VertragPos`). This means:
- Every column that exists in `VertragKopf` must also exist in `VertragKopfVersions` with identical data types
- Every column that exists in `VertragPos` must also exist in `VertragPosVersions` with identical data types
- The only exceptions are system columns (`I3D`, `OriginalI3D`) which are handled specially
- Additional versioning columns are added: `OriginalI3D` (references original record) and `KopfVersionsI3D` (for position tables)
**Contract Version Creation Process:**
When a contract version is saved (using `AssetHeadDAO.SaveAssetVersion` mechanism):
```sql
-- Save contract header version
INSERT INTO VertragKopfVersions (all_columns_except_I3D, OriginalI3D)
SELECT all_columns_except_I3D, I3D AS OriginalI3D
FROM VertragKopf
WHERE I3D = @contractId
-- Save contract items version
INSERT INTO VertragPosVersions (all_columns_except_I3D, OriginalI3D, KopfVersionsI3D)
SELECT all_columns_except_I3D, I3D AS OriginalI3D, @headerVersionId AS KopfVersionsI3D
FROM VertragPos
WHERE VertragKopfI3D = @contractId
```
This enables complete audit trails of all contract modifications, rollback capability, and change tracking functionality.
**⚠️ Schema Maintenance Warning:** When adding new columns to `VertragKopf` or `VertragPos`, the identical columns must also be added to their corresponding version tables (`VertragKopfVersions` and `VertragPosVersions`). Failure to maintain this 1:1 correspondence will cause runtime errors during version saving operations.
#### Modern Contract Views
##### Contracts View (Contract Headers)
**Database View:** `dbo.Contracts`
**Purpose:** Clean, English-named view of VertragKopf for C# application use
**Benefits:**
- Consistent English naming convention
- Cleaner column structure
- Type safety improvements
- Better integration with ORM mapping
##### ContractItems View (Contract Items)
**Database View:** `dbo.ContractItems`
**Purpose:** Clean, English-named view of VertragPos for C# application use
##### Contract Version Views
**Version Views:**
- `ContractVersions` - Clean view of VertragKopfVersions
- `ContractItemVersions` - Clean view of VertragPosVersions
#### Contract Logging Integration
##### AnlageLog Integration
Contracts integrate with the centralized `AnlageLog` table for audit logging:
**Contract Log Entries:**
- `AnlageArt = 22` (Contract identifier)
- `AnlageI3D` - References contract I3D from VertragKopf
- Log entries for contract creation, modifications, billing events, renewals, and terminations
**Typical Log Events:**
- Contract creation and approval
- Billing interval changes
- Contingent modifications
- Device associations/removals
- Automated billing execution
- Contract renewals and terminations
## Business Logic Architecture
### ReceiptContractBL
**Location:** `src/backend/Centron.BL/Sales/Receipts/ContractLists/ReceiptContractBL.cs`
The `ReceiptContractBL` class provides contract-specific business logic extending the base receipt functionality.
#### Key Responsibilities
**Contract Invoice Management:**
- `DeactivateContractInvoice()`: Deactivate invoices generated from contracts
- `GetContractInfosFromInvoices()`: Extract contract information from invoices
- `ExistsInvoiceForContract()`: Check if invoices exist for a contract
**Device and Counter Management:**
- `ResetDeviceClickCounter()`: Reset click counters for printer/copier contracts
- `UpdateDeviceToContract()`: Associate devices with contracts
- `CheckCounterHistory()`: Validate counter readings history
**Contingent and Billing:**
- `ContractContingentBalanceCalculation()`: Calculate contingent balances
- `CalculateContingentWithRecalculationArticle()`: Handle contingent recalculations
- `UpdateContractContingentBalanceCalculationForReceiptChange()`: Adjust balances when receipts change
- `UpdateTakeRestAndOverBooking()`: Handle remainder and overbooking scenarios
**Master Data List Management:**
- `AddMasteDateListsToContract()`: Associate master data lists with contracts
- `CreateMasterDataListsForNewMspArticles()`: Create lists for new MSP articles
- `RemoveMasterDataList()`: Remove master data list associations
- `CheckRemovedMasterDataList()`: Validate removed associations
**Contract-Specific Item Processing:**
- `GetContractRelevantItems()`: Retrieve items relevant for contract billing
- `UpdatePriceForContractRelevantItem()`: Update pricing for contract items
- `SaveContractPositionCounter()`: Persist counter readings
- `SaveContractFreeCopies()`: Handle free copy allowances
### ContractSpecificLogic
**Location:** `src/backend/Centron.BL/Sales/Receipts/ContractLists/ContractSpecificLogic.cs`
This class implements contract-specific operations that are called by the main `ReceiptBL` through the `SpecificLogics` pattern.
### Related Business Logic Classes
#### ContractBL
**Location:** `src/backend/Centron.BL/Sales/CustomerAssets/Contracts/ContractBL.cs`
Handles broader contract asset management beyond the receipt functionality:
- Contract lifecycle management
- Device associations and management
- Contract analysis and reporting
- Integration with customer asset management
#### AutomaticFacturaBL.Contracts
**Location:** `src/backend/Centron.BL/Sales/CustomerAssets/AutomaticFactura/AutomaticFacturaBL.Contracts.cs`
Manages automated billing for contracts:
- Automatic invoice generation based on billing intervals
- RMM (Remote Monitoring and Management) integration
- Billing parameter calculation
- Multi-interval billing support
## Contract Workflows
### Contract Creation Process
1. **Initialize Contract**
```csharp
var contract = new ReceiptContract
{
CustomerI3D = customerId,
Date = DateTime.Now,
BillingIntervalKind = BillingIntervalKinds.Monthly,
BillingIntervalDuration = 1,
AutomatedBilling = true
};
```
2. **Configure Billing Parameters**
- Set billing intervals and calculation methods
- Define payment conditions and terms
- Configure contingent limits if applicable
3. **Add Contract Items**
- Products and services to be provided
- Pricing and quantity information
- Device associations for maintenance contracts
4. **Set Up Automation**
- Enable automated billing if required
- Configure renewal settings
- Set up monitoring and alerts
### Automated Billing Process
The automated billing system (`AutomaticFacturaBL`) processes contracts based on their billing intervals:
1. **Contract Evaluation**
- Check contracts due for billing
- Validate billing parameters and dates
- Verify customer and contract status
2. **Invoice Generation**
- Create invoice based on contract items
- Apply pricing rules and calculations
- Handle contingent deductions
3. **Post-Processing**
- Update contract billing dates
- Generate documents and notifications
- Update contingent balances
### Device Management Integration
For maintenance and service contracts:
1. **Device Association**
- Link devices to contracts through master data lists
- Track serial numbers and device information
- Monitor device status and warranty information
2. **Counter Reading Management**
- Collect meter readings for copiers/printers
- Calculate usage-based billing amounts
- Handle free copy allowances and overages
3. **Service Integration**
- Connect with RMM systems for automated data collection
- Process device monitoring data
- Generate alerts for maintenance requirements
## Configuration Options
### Billing Interval Configuration
**BillingIntervalKind Options:**
- `Daily`: Daily billing cycles
- `Monthly`: Monthly billing cycles
- `Quarterly`: Quarterly billing cycles
- `Yearly`: Annual billing cycles
**BillingIntervalDuration:**
- Number of intervals (e.g., 3 months for quarterly when kind is Monthly)
- Supports flexible billing periods
### Calculation Methods
**ContractCalculationKind Options:**
- Standard calculation methods for different contract types
- Custom calculation logic for specialized scenarios
**ContractNeedCalcKind:**
- Defines calculation requirements and triggers
- Controls when recalculations are needed
## Integration Points
### Customer Asset Management
- Integration with device and asset tracking systems
- Warranty and maintenance schedule management
- Service history and documentation
### Accounting System
- Automated journal entry generation for contract billing
- Revenue recognition for service contracts
- Contingent liability tracking
### External Systems
- **RMM Integration**: Remote monitoring and management systems
- **Device APIs**: Direct device communication for counter readings
- **Customer Portals**: Web-based contract management interfaces
## Performance Considerations
### Billing Performance
- **Batch Processing**: Large contract sets processed in batches
- **Parallel Processing**: Multiple contracts processed simultaneously where possible
- **Caching**: Frequently accessed contract data cached for performance
### Database Optimization
- **Indexed Relationships**: Foreign keys properly indexed
- **Partitioning**: Large contract tables partitioned by date ranges
- **Archive Strategy**: Old contract data archived for performance
## Security and Compliance
### Access Control
- **Role-Based Permissions**: Different access levels for contract operations
- **Branch Isolation**: Contracts accessible only to authorized branches
- **Customer Isolation**: Cross-customer data protection
### Audit Requirements
- **Change Tracking**: Complete audit trail for all contract modifications
- **Billing History**: Detailed logging of all billing operations
- **Compliance Reporting**: Support for regulatory reporting requirements
## Best Practices
### Contract Design
- **Clear Billing Intervals**: Use consistent and predictable billing cycles
- **Contingent Management**: Monitor contingent usage to prevent overruns
- **Device Integration**: Properly associate devices for accurate billing
### Development Guidelines
- **Use ContractBL**: Leverage existing contract business logic
- **Handle Contingents**: Always consider contingent impacts in calculations
- **Validate Intervals**: Ensure billing interval consistency
- **Test Automation**: Thoroughly test automated billing scenarios
### Troubleshooting
- **Billing Issues**: Check interval configuration and calculation settings
- **Device Problems**: Verify master data list associations
- **Performance Issues**: Review indexing and query optimization
- **Integration Failures**: Validate external system connections and data formats
@@ -0,0 +1,356 @@
# Receipt Search Architecture
This document explains how the receipt search system works in the c-entron.NET backend, including filter application, shared logic across receipt types, and how to add new searchable properties.
## Overview
The receipt search system provides a unified search interface across all receipt types (offers, orders, delivery lists, invoices, contracts, credit vouchers, pickup lists, and supplier receipts). It uses a configurable, extensible architecture that allows different receipt types to implement their own search logic while sharing common filtering capabilities.
## Architecture Components
### 1. REST API Layer
**Entry Point:** `CentronRestService.SearchReceiptsThroughPaging`
- **Location:** `src/webservice/Centron.Host/Services/CentronRestServiceParts/CentronRestService.Receipts.cs`
- **Method:** `SearchReceiptsThroughPaging(Request<SearchReceiptsThroughPagingRequest> request)`
```csharp
public Response<ReceiptSearchItemPagingDTO> SearchReceiptsThroughPaging(Request<SearchReceiptsThroughPagingRequest> request)
{
var result = this.Session.GetBL<ReceiptSearchWebServiceBL>().SearchReceipts(
this.GetLoggedInUserByTicket(request.Ticket),
request.Data.Filter,
request.Data.Page,
request.Data.EntriesPerPage);
return Response<ReceiptSearchItemPagingDTO>.FromBLResult(result);
}
```
### 2. Business Logic Layer
**Primary Class:** `ReceiptSearchWebServiceBL`
- **Location:** `src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptSearch/ReceiptSearchWebServiceBL.cs`
- **Responsibility:** Coordinates search operations, handles pagination, and manages user context
```csharp
public Result<ReceiptSearchItemPagingDTO> SearchReceipts(LoggedInUser user,
ReceiptSearchFilter filter, int page, int entriesPerPage)
{
var receipts = new ReceiptSearcher(this.Session).SearchReceipts(filter, user);
// Apply pagination and return results
ReceiptSearchItemPagingDTO pagingDTO = new ReceiptSearchItemPagingDTO()
{
Count = receipts.Count,
CurrentPage = page,
PageCount = (int)Math.Ceiling(receipts.Count/(decimal) entriesPerPage),
Result = receipts.OrderByDescending(o => o.Date).Skip((page - 1) * entriesPerPage).Take(entriesPerPage).ToList()
};
return Result<ReceiptSearchItemPagingDTO>.AsSuccess(pagingDTO);
}
```
### 3. Core Search Engine
**Primary Class:** `ReceiptSearcher`
- **Location:** `src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptSearch/ReceiptSearcher.cs`
- **Responsibility:** Executes searches across all receipt types using configuration-driven SQL generation
#### Key Features:
- **Multi-Receipt Type Support:** Searches across multiple receipt types simultaneously
- **Configuration-Driven:** Uses `ReceiptSearchConfiguration` classes for each receipt type
- **Raw SQL Execution:** Generates and executes optimized SQL queries for performance
- **User Context Handling:** Applies user-specific filters (web accounts, branches, permissions)
#### Search Process:
1. **Filter Preparation:** Adjusts filter based on user context (web accounts, permissions)
2. **Configuration Iteration:** Loops through all receipt type configurations
3. **SQL Generation:** Creates receipt-type-specific SQL queries with parameters
4. **Query Execution:** Executes raw SQL with 5-minute timeout
5. **Result Aggregation:** Combines results from all receipt types
6. **Result Sorting:** Orders by ObjectKind, then by Number descending
```csharp
public IList<ReceiptSearchItemDTO> SearchReceipts(ReceiptSearchFilter filter, LoggedInUser user)
{
var result = new List<ReceiptSearchItemDTO>();
this.PrepareFilterForWebAccounts(filter, user);
foreach (var configuration in this._receiptSearchConfigurations)
{
if (filter.ReceiptKinds == null || filter.ReceiptKinds.Count == 0 || filter.ReceiptKinds.Contains(configuration.ReceiptKind))
{
var query = this.CreateSqlStatementAndParameters(configuration, filter, user);
if (query == null) continue; // Receipt type doesn't support this filter
var sqlStatement = query.Item1;
var parameters = query.Item2;
var receipts = this._rawSqlAccessDAO.ExecuteQuery<ReceiptSearchItemDTO>(sqlStatement, parameters, timeout: TimeSpan.FromMinutes(5));
result.AddRange(receipts);
}
}
return result.OrderBy(f => f.ObjectKind).ThenByDescending(f => f.Number).ToList();
}
```
### 4. Filter Definition
**Class:** `ReceiptSearchFilter`
- **Location:** `src/backend/Centron.Interfaces/Sales/Receipts/ReceiptSearch/ReceiptSearchFilter.cs`
- **Responsibility:** Defines all available search criteria
#### Available Filter Properties:
- **Basic Search:** `SearchText`, `ReceiptNumber`, `ReceiptNumbers`
- **Date Range:** `DateFrom`, `DateTo`, `ChangedAfterDate`
- **Account/Customer:** `AccountI3D`, `AccountNumbers`, `AccountName`
- **Receipt Types:** `ReceiptKinds` (controls which receipt types to search)
- **Status:** `IncludeClosedReceipts`, `OnlyOwn`, `OnlyOwnBranch`
- **Financial:** `GrossPriceFrom`, `GrossPriceTo`, `PaymentConditionI3D`, `DeliveryConditionI3D`
- **Specialized:** `HourlySurchargeRateI3Ds`, `ContractKindI3Ds`, `ArticleI3Ds`, `CampaignI3D`
- **Items:** `SearchInReceiptItemText`, `ReceiptItemI3D`
- **Advanced:** `IsCart`, `OnlyNonCarts`, `IsDownPaymentInvoice`, `IsReceiptTemplate`
### 5. Configuration System
**Base Class:** `ReceiptSearchConfiguration`
- **Location:** `src/backend/Centron.BL/WebServices/Sales/Receipts/ReceiptSearch/ReceiptSearchConfiguration.cs`
- **Responsibility:** Defines the contract for receipt-type-specific search configurations
#### Configuration Properties:
- **Basic Properties:**
- `ReceiptKind`: Identifies the receipt type (CentronObjectKindNumeric)
- `GetBaseSelectStatement()`: Returns the base SELECT query for this receipt type
- `OnlyActiveWhereStatement`: SQL for filtering active receipts
- **Filter WHERE Statements:** Each filter property has a corresponding WHERE clause property:
- `AccountI3DWhereStatement`: SQL for filtering by account
- `ReceiptNumberWhereStatement`: SQL for filtering by receipt number
- `DateFromWhereStatement`, `DateToWhereStatement`: Date range filtering
- `SearchTextWhereStatement`: Full-text search implementation
- And many more...
- **Permission Integration:**
- `ShowRight`: Required right to view receipts of this type
- `OnlyOwnRight`: Right that restricts to user's own receipts
- `OnlyOwnBranchRight`: Right that restricts to user's branch
#### Receipt Type Configurations:
- `OfferReceiptSearchConfiguration` - Offers (AngKopf)
- `OrderReceiptSearchConfiguration` - Orders (AufKopf)
- `DeliveryListReceiptSearchConfiguration` - Delivery Lists (LiefKopf)
- `InvoiceReceiptSearchConfiguration` - Invoices (RechKopf)
- `ContractReceiptSearchConfiguration` - Contracts (VertragKopf)
- `CreditVoucherReceiptSearchConfiguration` - Credit Vouchers (GutKopf)
- `PickupListReceiptSearchConfiguration` - Pickup Lists (AbholKopf)
- Plus supplier variants for each type
## SQL Generation Process
The `ReceiptSearcher.CreateSqlStatementAndParameters` method builds SQL queries dynamically based on the provided filter and receipt type configuration:
### 1. Base Query Construction
```csharp
var baseSelect = configuration.GetBaseSelectStatement(filter);
var builder = new StringBuilder(baseSelect);
```
### 2. Filter Application
For each filter property that has a non-null/non-empty value:
```csharp
if (filter.AccountI3D != null && filter.AccountI3D > 0)
{
var accountWhereStatement = configuration.AccountI3DWhereStatement;
if (string.IsNullOrWhiteSpace(accountWhereStatement))
return null; // This receipt type doesn't support this filter
builder.AppendLine(accountWhereStatement);
parameters.Add(new NamedQueryParameter("AccountI3D", filter.AccountI3D, NHibernateUtil.Int32));
}
```
### 3. Permission Checks
```csharp
if (configuration.ShowRight.HasValue && !this._appRightsBL.HasRight(user.AppUser, configuration.ShowRight.Value))
{
return null; // User doesn't have permission to search this receipt type
}
```
### 4. Active Receipts Filter
```csharp
if (!filter.IncludeClosedReceipts)
{
builder.AppendLine(configuration.OnlyActiveWhereStatement);
}
```
## Adding New Filter Properties
To add a new searchable property (e.g., `IsHiddenInHelpdesk`), follow these steps:
### Step 1: Add to ReceiptSearchFilter
Add the new property to `ReceiptSearchFilter.cs`:
```csharp
[DataMember]
public bool? IsHiddenInHelpdesk { get; set; }
```
### Step 2: Add to Base Configuration
Add the corresponding WHERE statement property to `ReceiptSearchConfiguration.cs`:
```csharp
public virtual string IsHiddenInHelpdeskWhereStatement { get; } = null;
```
### Step 3: Update Receipt Type Configurations
For each receipt type that supports the new filter, implement the WHERE statement:
**Example for ContractReceiptSearchConfiguration:**
```csharp
public override string IsHiddenInHelpdeskWhereStatement => "AND AK.IsHiddenInHelpdesk = :IsHiddenInHelpdesk";
```
### Step 4: Update SQL Generation
Add the filter logic to `ReceiptSearcher.CreateSqlStatementAndParameters`:
```csharp
if (filter.IsHiddenInHelpdesk != null)
{
var isHiddenInHelpdeskWhere = configuration.IsHiddenInHelpdeskWhereStatement;
if (string.IsNullOrWhiteSpace(isHiddenInHelpdeskWhere))
return null; // This receipt type doesn't support this filter
builder.AppendLine(isHiddenInHelpdeskWhere);
parameters.Add(new NamedQueryParameter("IsHiddenInHelpdesk", filter.IsHiddenInHelpdesk.Value, NHibernateUtil.Boolean));
}
```
### Step 5: Database Schema Requirements
Ensure the underlying database tables and views include the new column:
- **Tables:** Add to base tables (e.g., `VertragKopf`) and version tables (e.g., `VertragKopfVersions`)
- **Views:** Update views (e.g., `Contracts`, `ContractVersions`) to include the new column
## Shared Logic Across Receipt Types
The system achieves code reuse through several mechanisms:
### 1. Configuration-Driven Architecture
- Common filter logic is implemented once in `ReceiptSearcher`
- Receipt-type-specific behavior is encapsulated in configuration classes
- New receipt types can be added by implementing a new configuration class
### 2. Base SELECT Queries
Each configuration provides a standardized SELECT query that returns `ReceiptSearchItemDTO` properties:
```csharp
public override string GetBaseSelectStatement(ReceiptSearchFilter filter)
{
return @"
SELECT
I3D = AK.I3D,
ObjectKind = 22,
Number = AK.Nummer,
Version = AK.Version,
Caption = AK.Zusatztext,
Date = AK.Datum,
Receiver = AK.Empfaenger,
AccountI3D = AK.KundenID,
-- ... more fields
FROM VertragKopf AK
-- ... joins
WHERE 1=1"; // Base WHERE clause for dynamic filter appending
}
```
### 3. Parameter Handling
- All configurations use named parameters (`:ParameterName`)
- Parameter types are consistently defined using NHibernate types
- Array parameters support IN clauses for multiple values
### 4. Permission Integration
- Rights checking is standardized across all receipt types
- Each configuration can define specific rights for viewing, own-only, and branch-only access
- Permission failures result in null queries (no results for that receipt type)
## Performance Considerations
### 1. Raw SQL Execution
- Uses raw SQL instead of LINQ/HQL for optimal performance
- Timeout set to 5 minutes for complex searches
- Transaction isolation levels configured for consistency
### 2. Pagination
- Results are paginated at the business logic level
- Sorting is applied after aggregation (may impact performance for large result sets)
- Consider implementing database-level pagination for very large datasets
### 3. Index Requirements
- Ensure all filterable columns are properly indexed
- Foreign key columns should have indexes
- Date range queries benefit from composite indexes
### 4. Query Optimization
- Each receipt type can optimize its base query independently
- Complex joins are handled in the base SELECT statement
- WHERE clauses are appended dynamically to avoid query plan issues
## Security and Permissions
### 1. User Context Handling
- Web account users are automatically filtered to their associated customer
- Employee users can be restricted by branch or ownership
- Permission checking prevents unauthorized access to receipt types
### 2. SQL Injection Prevention
- All user input is parameterized
- No dynamic SQL concatenation with user values
- Named parameters ensure type safety
### 3. Branch Isolation
- Branch-specific filtering can be enforced per receipt type
- User's branch context is automatically applied where configured
## Testing Strategies
### 1. Unit Testing
- Test individual configuration classes in isolation
- Mock filter scenarios for comprehensive coverage
- Verify SQL generation for all filter combinations
### 2. Integration Testing
- Test complete search workflows with real data
- Verify permission enforcement
- Test pagination and sorting behavior
### 3. Performance Testing
- Measure query execution times for large datasets
- Test timeout behavior under load
- Validate index effectiveness
## Future Enhancements
### 1. Elasticsearch Integration
- Consider moving to Elasticsearch for full-text search capabilities
- Maintain SQL for structured filtering
- Hybrid approach for optimal performance
### 2. Real-time Filtering
- Implement WebSocket-based real-time updates
- Consider caching frequently accessed search results
### 3. Advanced Search Features
- Saved search queries
- Search history
- Search result highlighting
## Conclusion
The receipt search system provides a robust, extensible architecture for searching across all receipt types in the c-entron.NET system. By following the established patterns for adding new filter properties, developers can easily extend search capabilities while maintaining consistency and performance across the entire system.
The configuration-driven approach ensures that new receipt types can be added with minimal impact on existing code, while the shared search logic provides consistency and maintainability across all receipt types.
@@ -0,0 +1,371 @@
# Receipts Backend Architecture
This document describes the generic architecture and components of the receipts system in the c-entron.NET backend, which provides a unified foundation for all receipt types including offers, orders, delivery lists, invoices, contracts, and credit vouchers.
## Overview
The receipts system follows a layered architecture pattern with a shared base implementation that is extended by specific receipt types. All receipt types inherit from common base classes and share fundamental operations while providing specialized functionality through their own business logic classes.
## Core Components
### Entity Layer
#### ReceiptBase Abstract Class
**Location:** `src/backend/Centron.Entities/Entities/Sales/Receipts/ReceiptBase.cs`
The `ReceiptBase` abstract class serves as the foundation for all receipt entities in the system. It inherits from `BaseEntity` and implements the `IReceiptBase` interface.
**Key Properties:**
- **Receipt Header Information:** Number, Date, Version, State, Editor
- **Branch Information:** BranchI3D, BranchOrigin
- **Currency Information:** CurrencyI3D, CurrencyFactor, CurrencyString, ExclusiveOfVAT
- **Contact Information:** Receiver, Phone, Fax, Email
- **Address Information:** AddressI3D, ContactPersonI3D, Street, PostOfficeBox, Zip, City, ContactName, CountryI3D
- **Audit Fields:** CreatedByI3D, CreatedAt, ChangedByI3D, ChangedAt, Application Version tracking
- **System Fields:** ConcurrencyControlGuid, CustomUpdateArticlePricesAndTexts
**Abstract Methods:**
- `ReceiptKind`: Returns the specific receipt type (CentronObjectKindNumeric)
- `GetReceiptItems()`: Returns all receipt items
- `SetReceiptItems()`: Sets receipt items collection
- `AddItem()`: Adds a new item to the receipt
- `RemoveItem()`: Removes an item from the receipt
#### Receipt Types Hierarchy
All receipt types extend `ReceiptBase` and follow a consistent pattern of entity classes, database tables, and views:
| Receipt Type | Entity Class | Database Table | Database View | Items Table | Items View |
|--------------|--------------|----------------|---------------|-------------|------------|
| **Offers** | `ReceiptOffer` | `AngKopf` | `Offers` | `AngPos` | `OfferItems` |
| **Orders** | `ReceiptOrder` | `AufKopf` | `Orders` | `AufPos` | `OrderItems` |
| **Delivery Lists** | `ReceiptDeliveryList` | `LiefKopf` | `DeliveryLists` | `LiefPos` | `DeliveryListItems` |
| **Invoices** | `ReceiptInvoice` | `RechKopf` | `Invoices` | `RechPos` | `InvoiceItems` |
| **Contracts** | `ReceiptContract` | `VertragKopf` | `Contracts` | `VertragPos` | `ContractItems` |
| **Credit Vouchers** | `ReceiptCreditVoucher` | `GutKopf` | `CreditVouchers` | `GutPos` | `CreditVoucherItems` |
| **Pickup Lists** | `ReceiptPickupList` | `AbholKopf` | `PickupLists` | `AbholPos` | `PickupListItems` |
**Entity Locations:**
- `src/backend/Centron.Entities/Entities/Sales/Receipts/Offers/ReceiptOffer.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/Orders/ReceiptOrder.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/DeliveryLists/ReceiptDeliveryList.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/Invoices/ReceiptInvoice.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/ContractLists/ReceiptContract.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/CreditVouchers/ReceiptCreditVoucher.cs`
- `src/backend/Centron.Entities/Entities/Sales/Receipts/PickupLists/ReceiptPickupList.cs`
## Database Schema
### Dual Layer Architecture: Tables and Views
The receipts system uses a dual-layer database architecture consisting of legacy tables and modern views. This design maintains backward compatibility while providing cleaner interfaces for the C# application.
#### Legacy Tables (German Names)
The original database tables use German naming conventions and contain historical structure:
**Header Tables (*Kopf):**
- `AngKopf` - Offer headers
- `AufKopf` - Order headers
- `LiefKopf` - Delivery list headers
- `RechKopf` - Invoice headers
- `VertragKopf` - Contract headers
- `GutKopf` - Credit voucher headers
- `AbholKopf` - Pickup list headers
**Position Tables (*Pos):**
- `AngPos` - Offer items
- `AufPos` - Order items
- `LiefPos` - Delivery list items
- `RechPos` - Invoice items
- `VertragPos` - Contract items
- `GutPos` - Credit voucher items
- `AbholPos` - Pickup list items
**Version Tables (*Versions):**
Each receipt type maintains version history through dedicated version tables:
- `AngKopfVersions` / `AngPosVersions` - Offer version history
- `AufKopfVersions` / `AufPosVersions` - Order version history
- `LiefKopfVersions` / `LiefPosVersions` - Delivery list version history
- `RechKopfVersions` / `RechPosVersions` - Invoice version history
- `VertragKopfVersions` / `VertragPosVersions` - Contract version history
- `GutKopfVersions` / `GutPosVersions` - Credit voucher version history
- `AbholKopfVersions` / `AbholPosVersions` - Pickup list version history
#### Modern Views (English Names)
For C# application compatibility, cleaner views with English names are used:
**Header Views:**
- `Offers` - Clean view of AngKopf
- `Orders` - Clean view of AufKopf
- `DeliveryLists` - Clean view of LiefKopf
- `Invoices` - Clean view of RechKopf
- `Contracts` - Clean view of VertragKopf
- `CreditVouchers` - Clean view of GutKopf
- `PickupLists` - Clean view of AbholKopf
**Item Views:**
- `OfferItems` - Clean view of AngPos
- `OrderItems` - Clean view of AufPos
- `DeliveryListItems` - Clean view of LiefPos
- `InvoiceItems` - Clean view of RechPos
- `ContractItems` - Clean view of VertragPos
- `CreditVoucherItems` - Clean view of GutPos
- `PickupListItems` - Clean view of AbholPos
**Version Views:**
- `OfferVersions` / `OfferItemVersions` - Offer version views
- `OrderVersions` / `OrderItemVersions` - Order version views
- `DeliveryListVersions` / `DeliveryListItemVersions` - Delivery list version views
- `InvoiceVersions` / `InvoiceItemVersions` - Invoice version views
- `ContractVersions` / `ContractItemVersions` - Contract version views
- `CreditVoucherVersions` / `CreditVoucherItemVersions` - Credit voucher version views
- `PickupListVersions` / `PickupListItemVersions` - Pickup list version views
### Shared Logging Infrastructure
#### AnlageLog Table
**Purpose:** Centralized logging for all receipt types
**Structure:** Shared table with receipt type differentiation
**Key Columns:**
- `AnlageI3D` - References the specific receipt's I3D
- `AnlageArt` - Receipt type identifier (corresponds to ObjectKind)
- Log entry details and timestamps
**AnlageArt Values:**
- `1` = Offer
- `2` = Order
- `3` = Delivery List
- `4` = Invoice
- `5` = Pickup List
- `6` = Credit Voucher
- `22` = Contract
This pattern (`ObjectI3D` + `ObjectKind` / `AnlageI3D` + `AnlageArt`) is used throughout the system for shared references across different entity types.
### Schema Maintenance
#### Version Tables: 1:1 Copies of Original Tables
**Critical Requirement:** Version tables (`*KopfVersions`, `*PosVersions`) are exact 1:1 copies of their corresponding original tables. This means **every column that exists in the base table must also exist in the version table** with identical structure and data types.
**Version Table Structure:**
- Contains all columns from the original table
- Excludes certain system columns (I3D, OriginalI3D)
- Adds `OriginalI3D` column to reference the original record
- Adds `KopfVersionsI3D` column (for *Pos version tables) to reference the header version
**Versioning Implementation Example:**
The versioning mechanism (as seen in `AssetHeadDAO.SaveAssetVersion`) works by:
```sql
-- Copy header record to version table
INSERT INTO AngKopfVersions (all_columns_except_I3D, OriginalI3D)
SELECT all_columns_except_I3D, I3D AS OriginalI3D
FROM AngKopf
WHERE I3D = @receiptId
-- Copy all item records to version table
INSERT INTO AngPosVersions (all_columns_except_I3D, OriginalI3D, KopfVersionsI3D)
SELECT all_columns_except_I3D, I3D AS OriginalI3D, @headerVersionId AS KopfVersionsI3D
FROM AngPos
WHERE AngKopfI3D = @receiptId
```
#### Adding New Columns - Complete Checklist
When adding new columns to receipts, **all** of the following must be updated:
1. **Base Table:** Add column to the legacy table (e.g., `AngKopf`)
2. **Version Table:** Add the **identical column** to the version table (e.g., `AngKopfVersions`)
3. **Update Views:** Modify both the main view (e.g., `Offers`) and version view (e.g., `OfferVersions`) to include the new column
4. **Entity Classes:** Add the property to the C# entity class (e.g., `ReceiptOffer`) and version entity if applicable
5. **Mapping Classes:** Update NHibernate mapping classes for ORM functionality
6. **Temporary Legacy Entities:** Add the property to the matching `*Kopf` / `*Pos` temporary entity under `src/backend/Centron.Entities/Entities/DbEntities/`
7. **Temporary Entity Mappings:** Add the mapping to the matching class under `src/backend/Centron.DAO/Mappings/TemporaryEntities/`
8. **SaveReceipt Repository:** Copy the value in the receipt-type-specific `SaveReceipt*Repository` (`SynchronizeReceiptData` for header fields, `SynchronizeReceiptItemData` for item fields)
9. **DTOs and Interfaces:** Add the property to webservice DTOs and relevant receipt interfaces when the value crosses BL/WebService/UI boundaries
10. **Version Views:** Ensure version views (`OfferVersions`, `OfferItemVersions`) include the new column
**⚠️ Critical Warning:** Forgetting to add a column to the version table will cause runtime errors when the versioning system attempts to copy records. The `DoGetFieldList()` method dynamically generates field lists, so missing columns in version tables will break the INSERT statements.
**Critical Save Warning:** The normal NHibernate receipt entity mapping is not the only persistence path. Receipt saves go through legacy `SaveReceipt*Repository` classes, which synchronize the modern receipt entities into temporary legacy table entities (`RechKopf`, `RechPos`, `LiefKopf`, `LiefPos`, etc.) before writing to the database. If a new field is only added to the modern entity/view mapping but not to the temporary entity, temporary mapping, and `SaveReceipt*Repository`, the value may load correctly from the view but will not be persisted on save.
#### Version Table Maintenance Process
**For Header Tables (*Kopf → *KopfVersions):**
1. Add column to base table: `ALTER TABLE AngKopf ADD NewColumn datatype`
2. Add identical column to version table: `ALTER TABLE AngKopfVersions ADD NewColumn datatype`
3. Update corresponding views to include the new column
**For Item Tables (*Pos → *PosVersions):**
1. Add column to base table: `ALTER TABLE AngPos ADD NewColumn datatype`
2. Add identical column to version table: `ALTER TABLE AngPosVersions ADD NewColumn datatype`
3. Update corresponding views to include the new column
This strict 1:1 correspondence ensures that the automatic versioning system (`AssetHeadDAO.SaveAssetVersion` and similar methods) can create complete snapshots of receipt states for audit trails and change tracking.
### Business Logic Layer
#### ReceiptBL - Core Business Logic
**Location:** `src/backend/Centron.BL/Sales/Receipts/ReceiptBL.cs`
The `ReceiptBL` class provides the central business logic for all receipt operations. It contains over 10,000 lines of code handling comprehensive receipt management functionality.
**Key Responsibilities:**
- **CRUD Operations:** Generic methods for loading, searching, and saving receipts
- **Receipt Processing:** State management, workflow processing, validation
- **Item Management:** Adding, updating, removing receipt items
- **Price Calculations:** Tax calculations, discounts, currency conversions
- **Document Generation:** PDF generation, printing, email sending
- **Integration:** Connection with accounting systems, warehousing, customer management
- **Workflow Management:** Approval processes, state transitions
- **Reporting:** Export functionality (Excel, PDF)
**Core Methods:**
- `GetReceiptByI3D<T>(int receiptI3D)`: Generic receipt retrieval
- `GetReceipts<T>(IReceiptFilter filter)`: Search receipts with filtering
- `SaveReceipt<T>(T receipt)`: Generic receipt saving
- `DeleteReceipt(int receiptI3D, CentronObjectKindNumeric receiptKind)`: Receipt deletion
- `ExportReceiptToExcel()`: Excel export functionality
#### SpecificLogics Pattern
The `ReceiptBL` utilizes a `SpecificLogics` helper class that delegates specialized operations to receipt-type-specific business logic classes:
- **ContractSpecificLogic** for contracts
- **InvoiceSpecificLogic** for invoices
- **OrderSpecificLogic** for orders
- And similar classes for other receipt types
### Data Access Layer
#### Repository Pattern
Each receipt type has its own repository for data persistence:
- **SaveReceiptContractRepository** → `VertragKopf` & `VertragPos` tables
- **SaveReceiptInvoiceRepository** → `RechKopf` & `RechPos` tables
- **SaveReceiptOfferRepository** → `AngKopf` & `AngPos` tables
- **SaveReceiptOrderRepository** → `AufKopf` & `AufPos` tables
- **SaveReceiptDeliveryListRepository** → `LiefKopf` & `LiefPos` tables
- **SaveReceiptCreditVoucherRepository** → `GutKopf` & `GutPos` tables
- **SaveReceiptPickupListRepository** → `AbholKopf` & `AbholPos` tables
- And similar repositories for supplier receipt types
These repositories are a legacy persistence layer between the normal NHibernate receipt entities and the database. They create or update temporary table entities and explicitly assign many properties. When adding a persisted receipt header or item field, update the repository method that synchronizes that level:
- Header field: `SynchronizeReceiptData(...)`
- Item field: `SynchronizeReceiptItemData(...)`
Do not rely on AutoMapper or the modern NHibernate entity mapping for this save path. End-to-end tests are the preferred safety net for new receipt fields because they execute the database script, save through `ReceiptWebServiceBL.SaveReceipt(...)`, reload the receipt, and can assert the raw legacy table values.
#### Database Table Structure
All receipt types follow a consistent two-table pattern:
**Header Tables (*Kopf):**
- Contains receipt-level information (customer, dates, totals, etc.)
- Inherits from `ReceiptTable` base structure
- Primary key: `I3D` (identity column)
- Common audit fields: CreatedAt, ChangedAt, CreatedByI3D, ChangedByI3D
**Position Tables (*Pos):**
- Contains individual line items/positions
- Foreign key reference to header table (*KopfI3D)
- Article information, quantities, prices, and item-specific data
- Primary key: `I3D` (identity column)
- Position number: `Pos` (for ordering)
## Common Workflows
### Receipt Creation Process
1. **Initialize Receipt Entity** - Create new receipt instance with default values
2. **Set Header Information** - Customer, addresses, dates, currency
3. **Add Receipt Items** - Products/services with quantities and prices
4. **Calculate Totals** - Tax calculations, discounts, final amounts
5. **Validate Business Rules** - Check inventory, credit limits, etc.
6. **Save to Database** - Persist header and position records
7. **Generate Document** - Create PDF, send emails if required
### Receipt State Management
Receipts progress through defined states:
- **Draft** - Initial creation, can be freely modified
- **Released** - Approved for processing, limited modifications
- **Processed** - Finalized, minimal changes allowed
- **Cancelled** - Marked as cancelled, read-only
### Item Management
- **Dynamic Item Addition** - Items can be added at any time during draft state
- **Price Calculation** - Automatic recalculation of totals when items change
- **Inventory Integration** - Real-time stock checking and updates
- **Article Linking** - Connection to master article data
## Integration Points
### Customer Management
- Customer data integration for addresses and contact information
- Credit limit checking and payment term assignment
- Customer-specific pricing and discount structures
### Inventory System
- Real-time stock level checking
- Automatic inventory updates on receipt processing
- Serial number and barcode tracking
### Accounting System
- Automatic journal entry generation
- Tax calculation and reporting
- Integration with financial reporting systems
### Document Management
- PDF generation for all receipt types
- Email delivery capabilities
- Document archiving and retrieval
## Extensibility
### Adding New Receipt Types
To add a new receipt type:
1. **Create Entity Classes** - Header and position entities extending base classes
2. **Implement Business Logic** - Specific BL class with type-specific operations
3. **Create Database Tables** - Following the *Kopf/*Pos naming convention
4. **Add Repository Classes** - For data persistence operations
5. **Register with SpecificLogics** - Enable integration with core ReceiptBL
### Customization Points
- **Custom Fields** - Additional properties on receipt entities
- **Business Rules** - Custom validation and processing logic
- **Workflow Extensions** - Additional states and transitions
- **Integration Hooks** - Custom external system connections
## Performance Considerations
### Database Optimization
- **Indexed Foreign Keys** - All *KopfI3D references are indexed
- **Pagination Support** - Large result sets handled via paging
- **Query Optimization** - Efficient queries for common operations
### Memory Management
- **Lazy Loading** - Receipt items loaded on demand
- **Batch Operations** - Bulk processing for multiple receipts
- **Caching Strategy** - Frequently accessed data cached appropriately
## Security
### Access Control
- **User-based Permissions** - Role-based access to receipt functions
- **Branch Isolation** - Users can only access receipts from their branches
- **Audit Trail** - Complete tracking of all receipt changes
### Data Protection
- **Concurrency Control** - GUID-based optimistic locking
- **Data Validation** - Input validation and sanitization
- **Transaction Management** - ACID compliance for all operations
## Best Practices
### Development Guidelines
- **Use Generic Methods** - Leverage ReceiptBL generic operations where possible
- **Follow Inheritance Patterns** - Extend base classes rather than duplicating code
- **Implement Proper Error Handling** - Use try-catch blocks and meaningful error messages
- **Maintain Audit Trails** - Always populate CreatedBy/ChangedBy fields
### Testing Considerations
- **Unit Tests** - Test business logic methods in isolation
- **Integration Tests** - Test complete receipt workflows
- **Database Tests** - Verify data persistence and retrieval
- **Performance Tests** - Ensure acceptable response times under load