---
# System prepended metadata

title: calculator api

---




### activity based

```ts
function calculateEmissionByActivity(activity: ActivityDTO) : {
	calculatedAt: Date;
	totalEmission: number;
	materialEmission?: number;
	transportationEmission?: number;
}
```


```ts
// Database `cccdb`
// Type: subcollection
// Collection name `activities`
// Schema version 1.0

interface calculatedEmissionSnapshot {
	calculatedAt: Date;
	totalEmission: number;
	materialEmission?: number;
	transportationEmission?: number;
}

export interface ActivityDTO {
	uid: string;
	emissionSource: string;
	
	activityRemark?: string;
	vcaNodeId?: string;
	batchId?: string;
	
	materialBased?: {
		materialResourceType: string;
		unitAmount: number;
		unit: string;
	};
	
	// either
	transportationDistanceBased?: {
		transportVehicleResourceType: string;
		transportWeight: number;
		transportDistance: number;
		transportDepartPercentage: number;
		transportArrivePercentage: number;
	};
	// or
	transportationFuelAmountBased?: {
		transportFuelResourceType: string;
		transportFuelUnitAmount: number;
		transportFuelUnit: string;
	};
	
	  
	
	allocation: {
		allocationType: 'no_allocation' // default
		| 'energy_based'
		| 'physical_based'
		| 'economic_based'
		| 'other';
		mainProduct?: number;
		coProduct?: number;
		allocationPercentage: number; // default = 100%
	};  
	
	recycle: {
		recycleType:
		| 'no_recycle'
		| 'primary_manual_input'
		| 'secondary_tgo_material_based';
		recycleMaterial?: 'rubber' | 'paper' | 'plastic';
		recycleRate: number;
	};
	
	calculatedEmission?: calculatedEmissionSnapshot[];

	createdAt: Date;
	updatedAt: Date;
}
```

```ts
// Database `cccdb`
// Type: subcollection
// Collection name `emissionfactors`
// Collection name `emissionfactors` can be a standalone collection as a global emission factor library
// Or
// Under collection `businesses`, say, a business can have multiple emission factors
// Schema version 1.0


export interface GlobalWarmingPotentialDto {
	uid: string;
	commonName: string;
	formulaName: string;
	gwp100yr: number;
}

interface CustomEFValue {
	gwpId: string;
	value: number;
}

export interface EmissionFactorDto {
	uid: string;
	name: string;
	source: 'self' | 'supplier' | 'TGO' | 'predefined';
	type: 'co2_only' | 'multiple_ghgs';
	value: number | CustomEFValue[];
	
	unit: {
		id: string;
		name: string;
	};
	
	isSupportingProcess?: boolean;
	date?: Date;
	status?: 'active' | 'inactive';
	stage: 'unverified' | 'verified' | 'verifing';
	belongTo?: string; // in case of self, supplier, or predefined emission factors

	createdAt: Date;
	updatedAt: Date;
}
```

##### Unit Converter
(input unitAmount, input unit, resourceType) -> (desiredUnitAmount, desiredUnit)
1. convert to standard unit
	1. `unit.toSI()`
2. if unit is not in the same category
	1. cross-category conversion
		1. if desired unit is weight and input unit is in volume
			1. `desiredUnitAmount` = `unitAmount` x `resourceType.flexibilityOfUnit.density`
		2. if desired unit is volume and input unit is in weight
			1. `desiredUnitAmount` = `unitAmount` / `resourceType.flexibilityOfUnit.density`
		3. if desired unit is power and input unit is in time
			1. `desiredUnitAmount` = `unitAmount` x `resourceType.flexibilityOfUnit.powerConsumption`
3. `unit.to(desiredUnit)`


#### Flow
1. get `ActivityDTO` from parameter
2. set `is materialEmission` = 0, `transportationEmission` = 0
3. calculate material based emission
	1. if `materialBased`
		1. lookup `materialResourceType`
		2. ef = `materialResourceType.ef`
		3. if `ef.unit` !== `materialBased.unit`
			1. unit converter
		4. `materialEmission` = `convertedUnitAmount` * `ef.value`
	2. else skip
4. calculate transportation based emission
	1. if `transportationDistanceBased`
		1. select depart, arrival ef from `transportVehicleResourceType`, `transportDepartPercentage`, `transportArrivePercentage` -> look for it in system config json
		2. unit converter for `transportWeight`, `transportDistance`
		3. calculate depart load
			1. `transportWeight` x `transportDistance`
		4. calculate arrival load
			1. `depart load` / `maximumLoadTonne`
		4.`transportationEmission` = `depart load` x `depart ef` + `arrival load` x `arrived ef`
	2. else if `transportationFuelAmountBased`
		1. lookup `transportFuelResourceType`
		2. ef = `transportFuelResourceType.ef`
		3. if `ef.unit` !== `transportFuelUnit`
			1. unit converter
		4. `transportationEmission` = `convertedUnitAmount` * `ef.value`
	3. else skip
5. recycle
	1. activity category = waste or eol
		1. if `recycleType` === `no_recycle`
		2. else if `recycleType` === `primary_manual_input`
			1. `materialEmission` = `materialEmission` x `(1 - recycleRate)`
		3. else if `recycleType` === `secondary_tgo_material_based`
			1. if `recycleMaterial` === `rubber`
				1. `recycleRate` = xx
			2. else if `recycleMaterial` === `paper`
				1. `recycleRate` = xx
			3. else if `recycleMaterial` === `plastic`
				1. `recycleRate` = xx
			4. `materialEmission` = `materialEmission` x `(1 - recycleRate)`
6. allocation
	1. if `allocationType` === `no_allocation` skip
	2. else if `allocationType` === `energy_based` or `physical_based` or `economic_based`
		1. `allocationPercentage` = `mainProduct` / (`mainProduct` + `coProduct`)
	3. `materialEmission` = `materialEmission` x `allocationPercentage`
	4. `transportationEmission` = `transportationEmission` x `allocationPercentage`
7. output
	1. `timestamp`
	2. `totalEmission = materialEmission` +  `transportationEmission` 
	3. `materialEmission`
	4. `transportationEmission`


transportation resourcetype config
```js
[
	{
		transportVehicleResourceType: "รถบรรทุก 6 ล้อ ขนส่งแบบปกติ",
		maxmimumLoadTonne: 100, 
		efs: [
			{
				"loadPercentage": 100,
				// อาจจะ ref ไปหาตัวที่เก็บในระบบ
				"unitAmount": 2.34,
				"unit": "km"
			},
			{
				"loadPercentage": 75,
				"unitAmount": 2.34,
				"unit": "km"
			}
			...
		]
	}
	...
]
```


```mermaid
graph TD

A[Start] --> B[Get ActivityDTO]

B --> C[Set materialEmission = 0, transportationEmission = 0]

  

subgraph "Unit Converter"

UC1[Input: unitAmount, unit, resourceType] --> UC2[Convert to standard unit]

UC2 --> UC3{Units in same category?}

UC3 -->|No| UC4{Cross-category conversion}

UC4 -->|Weight to Volume| UC5[Use density]

UC4 -->|Volume to Weight| UC6[Use inverse density]

UC4 -->|Time to Power| UC7[Use powerConsumption]

UC3 -->|Yes| UC8[Convert to desired unit]

UC5 --> UC8

UC6 --> UC8

UC7 --> UC8

UC8 --> UC9[Output: desiredUnitAmount, desiredUnit]

end

  

C --> D{Is materialBased?}

D -->|Yes| E[Lookup materialResourceType]

E --> F[ef = materialResourceType.ef]

F --> G{ef.unit != materialBased.unit?}

G -->|Yes| H[Unit Converter]

G -->|No| I[materialEmission = amount * ef.value]

H --> I

D -->|No| J[Skip material emission]

I --> J

  

J --> K{Transportation type?}

K -->|Distance based| L1[Lookup transportVehicleResourceType]

L1 --> L2[Get transportDepartPercentage]

L2 --> L3[Get transportArrivePercentage]

L3 --> L4[Get depart ef and arrive ef from system config]

L4 --> M1[Calculate depart load: transportWeight * transportDistance]

M1 --> N1[Get maximumLoadTonne from system config]

N1 --> N2[Calculate arrival load: depart load / maximumLoadTonne]

N2 --> O1[Calculate depart emission: depart load * depart ef]

O1 --> O2[Calculate arrive emission: arrival load * arrive ef]

O2 --> O3[transportationEmission = depart emission + arrive emission]

K -->|Fuel amount based| P[Lookup transportFuelResourceType]

P --> Q[ef = transportFuelResourceType.ef]

Q --> R{ef.unit != transportFuelUnit?}

R -->|Yes| S[Unit Converter]

R -->|No| T[transportationEmission = amount * ef.value]

S --> T

K -->|None| U[Skip transportation emission]

O3 --> U

T --> U

  

U --> V{Is activity waste or EOL?}

V -->|Yes| W{Recycle Type?}

W -->|No recycle| X[Skip recycle]

W -->|Primary manual input| Y[materialEmission *= 1 - recycleRate]

W -->|Secondary TGO material based| Z{Recycle Material?}

Z -->|Rubber| AA[Set recycleRate for rubber]

Z -->|Paper| AB[Set recycleRate for paper]

Z -->|Plastic| AC[Set recycleRate for plastic]

AA --> AD[materialEmission *= 1 - recycleRate]

AB --> AD

AC --> AD

V -->|No| AE[Skip recycle]

X --> AE

Y --> AE

AD --> AE

  

AE --> AF{Allocation Type?}

AF -->|No allocation| AG[Skip allocation]

AF -->|Energy/Physical/Economic based| AH[Calculate allocationPercentage]

AH --> AI[Apply allocation to emissions]

AG --> AJ[Prepare output]

AI --> AJ

  

AJ --> AK[Set timestamp]

AK --> AL[Calculate totalEmission]

AL --> AM[Output materialEmission]

AM --> AN[Output transportationEmission]

AN --> AO[End]
```
### batch based

```ts
function calculateEmissionByฺBatch(activity: BatchDTO) : {
	calculatedAt: Date; 
	totalEmission: number; 
	materialEmission?: number; 
	transportationEmission?: number; 
}
```


```ts
// Database `cccdb`
// Type: sub of subcollection
// Collection name `batches`
// Under collection `businesses` and sub collection `products` say, a product can have multiple batches

// Schema version 1.0 
// Define BatchDto interface 
export interface BatchDto { 
	// Unique identifier
	uid: string;
	// Batch data
	name?: string;
	startDate?: Date;
	endDate?: Date;
	durationInDays?: number;
	status: 'active' | 'inactive' | 'deleted';
	stage: 'created' | 'on_progress' | 'finalized';
	// Update
	activities: ActivityDTO[];
	// Metadata
	createdBy: string;
	createdAt: Date;
	updatedBy?: string;
	updatedAt: Date;
}
```


### Flow
input:
(batch ID,  Output JSON Structure)
1. query data and aggregate into groups
    1. User request activities corresponding with Batch ID
    2. Lookup for batch with batch ID
    3. `activities` = `batch.activities`
    4. group `activities` by `chainId`
	    1. for each group, group by `vcaNodeId`
2. emission Calculation
    1. activities Level:
        1. use `Activity Based Calculator`
    2. subStages Level (Node)
        1. sum every activities
        2. output { `totalSubstageEmissions`, `totalSubstageMaterialBasedEmissions`, `totalSubstageTransportationBasedEmissions`} 
    3. stages Level:
        1. sum every substages emission
        2. output {`totalStageEmissions`, `totalStageMaterialBasedEmissions`, `totalStageTransportationBasedEmissions`}
	4. batch level
		1. sum every stages emission
        2. output {`timestamp`, `totalBatchEmissions`, `totalBatchMaterialBasedEmissions`, `totalBatchTransportationBasedEmissions`}

```mermaid
graph TD
    A[Start] --> B[Input: Batch ID, Output JSON Structure]
    
    subgraph "1. Query Data and Aggregate"
    B --> C[Query activities for Batch ID]
    C --> D[Lookup batch with batch ID]
    D --> E[activities = batch.activities]
    E --> F[Group activities by chainId]
    F --> G[For each chainId group, group by vcaNodeId]
    end
    
    subgraph "2. Emission Calculation"
    G --> H[Activities Level Calculation]
    H --> I[Use Activity Based Calculator]
    
    I --> J[Substages Level Calculation]
    J --> K[Sum emissions for all activities in substage]
    K --> L[Output substage emissions]
    L --> L1["{ totalSubstageEmissions, 
    totalSubstageMaterialBasedEmissions, 
    totalSubstageTransportationBasedEmissions }"]
    
    L1 --> M[Stages Level Calculation]
    M --> N[Sum emissions for all substages in stage]
    N --> O[Output stage emissions]
    O --> O1["{ totalStageEmissions, 
    totalStageMaterialBasedEmissions, 
    totalStageTransportationBasedEmissions }"]
    
    O1 --> P[Batch Level Calculation]
    P --> Q[Sum emissions for all stages in batch]
    Q --> R[Output batch emissions]
    R --> R1["{ timestamp, 
    totalBatchEmissions, 
    totalBatchMaterialBasedEmissions, 
    totalBatchTransportationBasedEmissions }"]
    end
    
    R1 --> S[End]
```