BPM Module
Türkçe
BPM (Business Process Management) modülü, iş ortakları, şubeler, kişiler, sözleşmeler,
sözleşme kalemleri, ürünler ve tahakkuk yönetimini kapsar. Entity hiyerarşisi:
BusinessPartner → Branch → Contact / Contract → ContractItem / Accrual.
Overview
The BPM module manages the business partner lifecycle — from partner registration through
contract management to periodic accrual generation. It runs as a standalone Spring Boot service
on port 8020 with context path /icbpm/services.
┌─────────────────────────────────────────────────────────┐
│ BPM Module — icbpm-services (port 8020) │
├─────────────────────────────────────────────────────────┤
│ Sub-Projects: │
│ ├ ICoSys-BPM-Types-1.0 → Enums (no Spring) │
│ ├ ICoSys-BPM-Entities-1.0 → JPA Entities │
│ ├ ICoSys-BPM-Entities-Dto-1.0 → DTOs │
│ └ ICoSys-BPM-Services-1.0 → Spring Boot Service │
│ │
│ Database: icbpm (MySQL 8) │
│ ID Table: s_icbpm_id │
└─────────────────────────────────────────────────────────┘
Entity Relationship Diagram
BusinessPartner (1) ─────→ (*) Branch
├──→ (*) Contact
└──→ (*) Contract
├──→ (*) ContractItem ──→ Product (optional)
└──→ (*) Accrual
All entities:
├── extend AbstractICEntity6
├── reference CrProcess (tenant, required)
└── use TableGenerator for ID generation
| Relationship |
Type |
Cascade |
Orphan Removal |
| BusinessPartner → Branch |
OneToMany |
ALL |
Yes |
| Branch → Contact |
OneToMany |
ALL |
Yes |
| Branch → Contract |
OneToMany |
ALL |
Yes |
| Contract → ContractItem |
OneToMany |
ALL |
Yes |
| Contract → Accrual |
OneToMany |
ALL |
Yes |
| ContractItem → Product |
ManyToOne |
— |
— |
| Branch → Country |
ManyToOne |
— |
— |
Entities
BusinessPartner
The root entity representing a customer or vendor.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK, auto-gen |
Primary key |
code |
String(20) |
UNIQUE per tenant |
Auto-generated partner code |
legalName |
String(255) |
NOT NULL |
Official legal name |
shortName |
String(100) |
|
Display/short name |
taxNumber |
String(20) |
UNIQUE per tenant |
VKN or TCKN |
taxOffice |
String(100) |
|
Tax office name |
isCustomer |
Boolean |
default FALSE |
Partner is a customer |
isVendor |
Boolean |
default FALSE |
Partner is a vendor |
externalId |
String(50) |
|
External system reference |
status |
BusinessPartnerStatus |
default ACTIVE |
Lifecycle status |
notes |
String(1000) |
|
Free-text notes |
Türkçe
isCustomer veya isVendor alanlarından en az biri true olmalıdır.
Her ikisi de false ise validateForCreate hata fırlatır.
Branch
A physical or logical branch belonging to a business partner.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
businessPartner |
BusinessPartner |
FK, NOT NULL |
Parent partner |
branchName |
String(100) |
NOT NULL, UNIQUE per partner |
Branch name |
billingTitle |
String(255) |
|
Invoice billing title |
addressText |
String(500) |
|
Full address |
country |
Country |
FK, optional |
Country reference |
city |
String(100) |
|
City name |
postalCode |
String(20) |
|
Postal code |
iban |
String(34) |
|
Bank IBAN |
einvoiceAlias |
String(50) |
|
GIB e-invoice alias |
phone |
String(20) |
|
Phone number |
email |
String(100) |
|
Email address |
isDefault |
Boolean |
default FALSE |
Default branch flag (unique per partner) |
status |
Boolean |
default TRUE |
Active status |
A person associated with a branch.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
branch |
Branch |
FK, NOT NULL |
Parent branch |
firstName |
String(50) |
NOT NULL |
First name |
lastName |
String(50) |
NOT NULL |
Last name |
title |
String(100) |
|
Job title |
email |
String(100) |
|
Email address |
mobilePhone |
String(20) |
|
Mobile phone |
officePhone |
String(20) |
|
Office phone |
roleType |
ContactRoleType |
default GENERAL |
Contact role |
isPrimary |
Boolean |
default FALSE |
Primary contact (unique per branch) |
hasConsent |
Boolean |
default FALSE |
KVKK marketing consent |
notes |
String(500) |
|
Free-text notes |
status |
Boolean |
default TRUE |
Active status |
Contract
A contractual agreement attached to a branch.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
branch |
Branch |
FK, NOT NULL |
Parent branch |
contractNo |
String |
UNIQUE per tenant |
Auto-generated contract number |
description |
String |
|
Contract title / description |
billingPeriod |
BillingPeriod |
|
Billing cycle type |
startDate |
LocalDate |
NOT NULL |
Contract start date |
endDate |
LocalDate |
|
Contract end date (≥ startDate) |
noticeDays |
Integer |
|
Notice period in days |
autoAccrual |
Boolean |
|
Auto-generate accruals flag |
currency |
String(3) |
|
ISO 4217 currency code |
paymentTermDays |
Integer |
|
Payment term in days |
indexationType |
IndexationType |
|
Price indexation type |
indexationRate |
BigDecimal(5,2) |
|
Custom indexation rate % |
invoiceLanguage |
String |
|
Invoice language |
status |
ContractStatus |
|
Contract lifecycle status |
notes |
String(1000) |
|
Free-text notes |
ContractItem
A line item within a contract, optionally linked to a product.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
contract |
Contract |
FK, NOT NULL |
Parent contract |
product |
Product |
FK, optional |
Product reference |
lineNo |
Integer |
NOT NULL |
Line number (ordering) |
description |
String(255) |
NOT NULL |
Item description |
billingPeriod |
BillingPeriod |
|
Billing cycle |
quantity |
BigDecimal(10,2) |
NOT NULL |
Quantity |
unit |
String |
|
Unit of measure |
unitPrice |
BigDecimal(18,4) |
NOT NULL |
Unit price |
discountRate |
BigDecimal(5,2) |
|
Discount percentage |
vatRate |
Integer |
|
VAT rate percentage |
currency |
String |
|
Currency code |
invoiceCurrency |
String(3) |
|
Invoice currency |
addMonthDesc |
Boolean |
|
Add month label to invoice |
separateInvoice |
Boolean |
|
Generate separate invoice |
invoiceLanguage |
String |
|
Invoice language |
notes |
String(500) |
|
Free-text notes |
accrualStatus |
Boolean |
|
Accrual generated flag |
status |
Boolean |
|
Active status |
Calculated fields (transient):
subtotal() = quantity × unitPrice
discountAmount() = subtotal × (discountRate / 100)
netAmount() = subtotal − discountAmount
vatAmount() = netAmount × (vatRate / 100)
totalAmount() = netAmount + vatAmount
Product
A reusable product or service definition.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
code |
String(50) |
UNIQUE, NOT NULL |
Auto-generated product code |
name |
String(200) |
NOT NULL |
Product / service name |
description |
String(1000) |
|
Detailed description |
category |
ProductCategory |
NOT NULL |
Product category |
defaultPrice |
BigDecimal(15,2) |
|
Default unit price |
currency |
String(3) |
|
ISO 4217 currency |
unit |
String(20) |
|
Unit of measure |
vatRate |
Integer |
|
Default VAT rate % |
sku |
String(100) |
|
SKU or external reference |
notes |
String(500) |
|
Free-text notes |
status |
Boolean |
default TRUE |
Active status |
Accrual
A periodic billing record generated from a contract.
| Field |
Type |
Constraints |
Description |
id |
Long |
PK |
Primary key |
contract |
Contract |
FK, NOT NULL |
Parent contract |
servicePeriod |
String(50) |
NOT NULL |
Period description (e.g., "JAN-2026") |
periodStart |
LocalDate |
NOT NULL |
Service period start |
periodEnd |
LocalDate |
NOT NULL |
Service period end |
netAmount |
BigDecimal(18,2) |
NOT NULL |
Net amount |
vatAmount |
BigDecimal(18,2) |
default 0 |
VAT amount |
totalAmount |
BigDecimal(18,2) |
NOT NULL |
Total including VAT |
currency |
String(3) |
default "TRY" |
ISO 4217 currency |
status |
AccrualStatus |
default DRAFT |
Workflow status |
approvedBy |
String(50) |
|
Approver user ID |
approvalDate |
Instant |
|
Approval timestamp |
invoiceRef |
String(50) |
|
External invoice reference |
invoiceDate |
LocalDate |
|
Invoice date |
syncLog |
String(2000) |
|
Integration sync log |
notes |
String(500) |
|
Free-text notes |
Enums
AccrualStatus
The accrual lifecycle workflow.
| Value |
Description |
DRAFT |
Created, awaiting approval |
APPROVED |
Approved, ready for invoicing |
INVOICED |
Sent to external invoicing system |
CANCELLED |
Cancelled |
FAILED |
Integration error during sync |
BusinessPartnerStatus
| Value |
Description |
ACTIVE |
Active and available |
PASSIVE |
Temporarily inactive |
SUSPENDED |
Suspended |
BLACKLISTED |
Blacklisted |
BLOCKED |
Blocked (compliance / payment) |
ContractStatus
| Value |
Description |
DRAFT |
Not yet active |
ACTIVE |
Currently in effect |
SUSPENDED |
Temporarily suspended |
EXPIRED |
End date has passed |
TERMINATED |
Terminated before end date |
RENEWED |
Replaced by a new contract |
BillingPeriod
| Value |
Description |
MONTHLY |
Monthly billing cycle |
QUARTERLY |
Every 3 months |
SEMI_ANNUAL |
Every 6 months |
YEARLY |
Annual |
ONE_TIME |
No recurrence |
RANDOM |
Custom / random dates |
IndexationType
| Value |
Description |
NONE |
Fixed price |
CPI |
TÜFE — Consumer Price Index |
PPI |
ÜFE — Producer Price Index |
USD |
USD exchange rate based |
EUR |
EUR exchange rate based |
CUSTOM |
Custom percentage |
22 values organized by department:
| Group |
Values |
| General |
GENERAL, OWNER |
| Management |
MANAGEMENT, PROJECT_MANAGER |
| Finance & Legal |
ACCOUNTING, LEGAL, CONTRACT |
| Commercial |
SALES, PURCHASING, MARKETING, BUSINESS_DEVELOPMENT |
| Operations |
TECHNICAL, LOGISTICS, WAREHOUSE, PRODUCTION, QUALITY |
| Support |
CUSTOMER_SERVICE, HR |
| Other |
OTHER |
ProductCategory
24+ categories covering physical goods, licensing, professional services, compliance,
operations, financial, and marketing categories.
Accrual Workflow
Türkçe
Tahakkuk akışı DRAFT → APPROVED → INVOICED şeklinde ilerler.
Sadece DRAFT durumundaki tahakkuklar güncellenebilir.
Silme işlemi yalnızca DRAFT veya CANCELLED için yapılabilir.
┌────────────┐
│ DRAFT │
└─────┬──────┘
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ │
┌────────────┐ ┌──────────┐ │
│ APPROVED │ │ CANCELLED│ │
└─────┬──────┘ └──────────┘ │
│ │
▼ │
┌────────────┐ │
│ INVOICED │ │
└────────────┘ │
│
┌────────────┐ │
│ FAILED │ ◄──────────────────┘
└────────────┘ (integration error)
| Transition |
Endpoint |
Rules |
| DRAFT → APPROVED |
POST /api/accrual/{id}/approve |
Sets approvedBy and approvalDate |
| APPROVED → INVOICED |
POST /api/accrual/{id}/invoice?invoiceRef=... |
Requires invoiceRef, sets invoiceDate |
| DRAFT/APPROVED → CANCELLED |
POST /api/accrual/{id}/cancel?reason=... |
Optional reason stored in syncLog |
| Any → FAILED |
Internal only |
Error message stored in syncLog |
Validation rules:
| Operation |
Allowed Status |
Error Code |
| Update |
DRAFT only |
error.accrual.cannot_update |
| Delete |
DRAFT or CANCELLED |
error.accrual.cannot_delete |
| Approve |
DRAFT only |
error.accrual.cannot_approve |
| Invoice |
APPROVED only |
error.accrual.cannot_invoice |
| Cancel |
DRAFT or APPROVED |
error.accrual.cannot_cancel |
REST API
Base path: /icbpm/services/api
BusinessPartner — /api/business-partner
| Method |
Endpoint |
Description |
| GET |
/{id} |
Find by ID |
| POST |
/ |
Create new partner |
| PUT |
/{id} |
Update partner |
| DELETE |
/{id} |
Delete partner |
| POST |
/list |
Paginated list with filter |
| GET |
/stats |
Entity statistics |
| GET |
/by-code/{crProcessId}/{code} |
Find by partner code |
| GET |
/by-tax/{crProcessId}/{taxNumber} |
Find by tax number |
Branch — /api/branch
| Method |
Endpoint |
Description |
| GET |
/{id} |
Find by ID |
| POST |
/ |
Create new branch |
| PUT |
/{id} |
Update branch |
| DELETE |
/{id} |
Delete branch |
| POST |
/list |
Paginated list |
| GET |
/stats |
Entity statistics |
Standard CRUD + list + stats endpoints.
Contract — /api/contract
| Method |
Endpoint |
Description |
| GET |
/{id} |
Find by ID |
| POST |
/ |
Create new contract |
| PUT |
/{id} |
Update contract |
| DELETE |
/{id} |
Delete contract |
| POST |
/list |
Paginated list |
| GET |
/stats |
Entity statistics |
| GET |
/by-no/{crProcessId}/{contractNo} |
Find by contract number |
| GET |
/by-branch/{branchId} |
Get contracts by branch |
| GET |
/by-partner/{businessPartnerId} |
Get contracts by partner |
| GET |
/active/{crProcessId} |
Get active contracts |
| GET |
/by-partner/{businessPartnerId}/active-count |
Count active contracts |
ContractItem — /api/contract-item
Standard CRUD + list endpoints.
Product — /api/product
Standard CRUD + list + stats endpoints.
Accrual — /api/accrual
| Method |
Endpoint |
Description |
| GET |
/{id} |
Find by ID |
| POST |
/ |
Create new accrual |
| PUT |
/{id} |
Update accrual (DRAFT only) |
| DELETE |
/{id} |
Delete accrual (DRAFT/CANCELLED only) |
| POST |
/list |
Paginated list |
| GET |
/stats |
Entity statistics |
| POST |
/{id}/approve |
Workflow: approve |
| POST |
/{id}/invoice?invoiceRef=... |
Workflow: mark invoiced |
| POST |
/{id}/cancel?reason=... |
Workflow: cancel |
| GET |
/by-contract/{contractId} |
Get accruals by contract |
| GET |
/by-partner/{businessPartnerId} |
Get accruals by partner |
| GET |
/by-status/{crProcessId}/{status} |
Get by status |
| GET |
/drafts/by-contract/{contractId} |
Get draft accruals |
Service Lifecycle Hooks
BusinessPartnerService
| Hook |
Logic |
validateForCreate |
Tax number uniqueness check; isCustomer OR isVendor must be true |
validateForUpdate |
Tax number uniqueness (excluding self); customer/vendor check |
beforeCreate |
Set CrProcess; auto-generate code via CodeGeneratorService |
BranchService
| Hook |
Logic |
validateForCreate |
businessPartnerId & branchName required; branch name unique within partner; default branch unique within partner |
validateForUpdate |
branchName required; name unique (excl. self); default unique (excl. self) |
beforeCreate |
Set CrProcess; resolve businessPartner; resolve country |
beforeUpdate |
Update country reference if changed |
ContractService
| Hook |
Logic |
validateForCreate |
branchId & startDate required; endDate ≥ startDate |
validateForUpdate |
startDate required; endDate ≥ startDate |
beforeCreate |
Set CrProcess; resolve branch; auto-generate contractNo |
AccrualService
| Hook |
Logic |
validateForCreate |
contractId required; validate common fields (period, amounts) |
validateForUpdate |
Only DRAFT status can be updated; validate common fields |
validateDeletion |
Only DRAFT or CANCELLED can be deleted |
beforeCreate |
Set CrProcess; resolve contract; set default status to DRAFT |
| Hook |
Logic |
validateForCreate |
branchId required; firstName/lastName required; primary contact unique within branch |
beforeCreate |
Set CrProcess; resolve branch |
Specification (Search & Filter)
BusinessPartnerSpecification
| Filter Field |
Operator |
code |
CONTAINS (LIKE) |
legalName |
CONTAINS |
taxNumber |
CONTAINS |
status |
EQUALS |
isCustomer |
EQUALS |
isVendor |
EQUALS |
creationDateFrom |
>= (date range) |
creationDateTo |
<= (date range) |
Global search fields: code, legalName, shortName, taxNumber
AccrualSpecification
| Filter Field |
Operator |
contractId |
EQUALS |
businessPartnerId |
EQUALS (via contract → branch → partner) |
status |
EQUALS |
currency |
EQUALS |
periodStartFrom |
>= (date range) |
periodStartTo |
<= (date range) |
invoiceRef |
CONTAINS |
hasInvoice |
IS NOT NULL / IS NULL |
Global search fields: servicePeriod, invoiceRef, contractNo
Türkçe
Tüm specification sınıfları ilk koşul olarak crProcessId (tenant isolation) filtresi uygular.
Bu filtre olmadan veri çekilemez.
Error Codes
All error constants are defined in ServiceErrorMsgCodes.java:
| Constant |
Message Key |
Context |
ERROR_FIELD_REQUIRED |
error.field_required |
General |
ERROR_ENTITY_NOT_FOUND |
error.not_found |
General |
ERROR_INVALID_TENANT |
error.invalid_tenant |
General |
ERROR_TAX_NUMBER_EXISTS |
error.business_partner.tax_number_exists |
BusinessPartner |
ERROR_MUST_BE_CUSTOMER_OR_VENDOR |
error.business_partner.must_be_customer_or_vendor |
BusinessPartner |
ERROR_BRANCH_NAME_EXISTS |
error.branch.name_exists |
Branch |
ERROR_BRANCH_DEFAULT_EXISTS |
error.branch.default_exists |
Branch |
ERROR_CONTACT_PRIMARY_EXISTS |
error.contact.primary_exists |
Contact |
ERROR_CONTRACT_INVALID_DATES |
error.contract.invalid_dates |
Contract |
ERROR_ACCRUAL_PERIOD_EXISTS |
error.accrual.period_exists |
Accrual |
ERROR_ACCRUAL_CANNOT_UPDATE |
error.accrual.cannot_update |
Accrual |
ERROR_ACCRUAL_CANNOT_DELETE |
error.accrual.cannot_delete |
Accrual |
ERROR_ACCRUAL_CANNOT_APPROVE |
error.accrual.cannot_approve |
Accrual |
ERROR_ACCRUAL_CANNOT_INVOICE |
error.accrual.cannot_invoice |
Accrual |
ERROR_ACCRUAL_CANNOT_CANCEL |
error.accrual.cannot_cancel |
Accrual |
All error codes are mapped to ErrorCodes.BPM_* enum constants in the global error code registry.
Configuration
Application Properties
| Property |
Value |
Description |
server.port |
8020 |
Dev server port |
server.servlet.context-path |
/icbpm/services |
Context path |
spring.datasource.url |
jdbc:mysql://localhost:3306/icbpm |
Database URL |
spring.jpa.hibernate.ddl-auto |
validate |
Schema validation only |
jwt.expiration.ms |
28800000 |
JWT expiry (8 hours) |
CORS (Development)
cors.allowed-origins=http://localhost:8080,http://localhost:5174
Rate Limiting
| Tier |
Requests/min |
| Public endpoints |
60 |
| API-Key endpoints |
100 |
| JWT endpoints |
200 |
Package Structure
com.icom.icosys.bpm
├── (root) → Entity classes
├── enums/ → Enum types
├── code/ → CodePrefix constants
├── dto/ → All DTO classes
└── service/
├── codes/ → ServiceErrorMsgCodes
└── zapi/
├── accrual/
│ ├── controller/ → AccrualController
│ ├── converter/ → EditDtoConverter, ListDtoConverter
│ ├── service/ → AccrualService
│ ├── specification/ → AccrualSpecification
│ └── AccrualRepository
├── branch/ → (same structure)
├── businesspartner/ → (same structure)
├── contact/ → (same structure)
├── contract/ → (same structure)
├── contractitem/ → (same structure)
└── product/ → (same structure)