### 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] ```