UNPKG

defarm-sdk

Version:

DeFarm SDK - On-premise blockchain data processing and tokenization engine for agriculture supply chain

223 lines (185 loc) 6.98 kB
import { BaseProcessor } from './BaseProcessor'; import type { Asset, ValidationError } from '../types'; /** * Processor for livestock assets (cattle, pigs, sheep, chickens) */ export class LivestockProcessor extends BaseProcessor { name = 'LivestockProcessor'; version = '1.0.0'; protected async validateCategory(asset: Asset): Promise<ValidationError[]> { const errors: ValidationError[] = []; // Validate subcategory const validSubcategories = ['cattle', 'pigs', 'sheep', 'chickens', 'goats']; if (!validSubcategories.includes(asset.subcategory)) { errors.push({ field: 'subcategory', message: `Invalid livestock subcategory. Must be one of: ${validSubcategories.join(', ')}`, code: 'INVALID_SUBCATEGORY' }); } // Validate weight if present const weightError = this.validateNumericField(asset, 'weight_kg', 0, 10000); if (weightError) errors.push(weightError); // Validate age if present const ageError = this.validateNumericField(asset, 'age_months', 0, 600); if (ageError) errors.push(ageError); // Validate birth date if present const birthDateError = this.validateDateField(asset, 'birth_date', false); if (birthDateError) errors.push(birthDateError); // Subcategory-specific validations switch (asset.subcategory) { case 'cattle': errors.push(...this.validateCattle(asset)); break; case 'pigs': errors.push(...this.validatePigs(asset)); break; case 'chickens': errors.push(...this.validateChickens(asset)); break; } return errors; } protected async processCategory(asset: Asset): Promise<Asset> { // Ensure standard livestock fields exist this.ensureDataField(asset, 'health_status', 'healthy'); this.ensureDataField(asset, 'vaccination_status', 'unknown'); // Calculate age from birth date if not provided if (asset.data.birth_date && !asset.data.age_months) { const birthDate = new Date(asset.data.birth_date); const now = new Date(); const ageMonths = Math.floor( (now.getTime() - birthDate.getTime()) / (1000 * 60 * 60 * 24 * 30) ); asset.data.age_months = ageMonths; } // Process based on subcategory switch (asset.subcategory) { case 'cattle': asset = this.processCattle(asset); break; case 'pigs': asset = this.processPigs(asset); break; case 'chickens': asset = this.processChickens(asset); break; } // Add processing timestamp asset.data.last_processed = new Date().toISOString(); return asset; } private validateCattle(asset: Asset): ValidationError[] { const errors: ValidationError[] = []; // Cattle-specific validations if (asset.data.breed) { const validBreeds = ['angus', 'hereford', 'nelore', 'brahman', 'simmental', 'limousin', 'charolais', 'other']; if (!validBreeds.includes(asset.data.breed.toLowerCase())) { errors.push({ field: 'data.breed', message: `Invalid cattle breed. Common breeds: ${validBreeds.join(', ')}`, code: 'INVALID_BREED' }); } } // Validate ear tag format if present if (asset.data.ear_tag) { const earTagPattern = /^[A-Z0-9]{3,20}$/; if (!earTagPattern.test(asset.data.ear_tag)) { errors.push({ field: 'data.ear_tag', message: 'Ear tag must be 3-20 alphanumeric characters', code: 'INVALID_EAR_TAG' }); } } return errors; } private validatePigs(asset: Asset): ValidationError[] { const errors: ValidationError[] = []; // Pig-specific validations if (asset.data.production_type) { const validTypes = ['breeding', 'finishing', 'nursery', 'farrow-to-finish']; if (!validTypes.includes(asset.data.production_type)) { errors.push({ field: 'data.production_type', message: `Invalid production type. Must be one of: ${validTypes.join(', ')}`, code: 'INVALID_PRODUCTION_TYPE' }); } } return errors; } private validateChickens(asset: Asset): ValidationError[] { const errors: ValidationError[] = []; // Chicken-specific validations if (asset.data.production_type) { const validTypes = ['broiler', 'layer', 'breeder', 'free-range']; if (!validTypes.includes(asset.data.production_type)) { errors.push({ field: 'data.production_type', message: `Invalid production type. Must be one of: ${validTypes.join(', ')}`, code: 'INVALID_PRODUCTION_TYPE' }); } } // Validate flock size if present const flockSizeError = this.validateNumericField(asset, 'flock_size', 1, 1000000); if (flockSizeError) errors.push(flockSizeError); return errors; } private processCattle(asset: Asset): Asset { // Auto-categorize based on age and gender if not specified if (!asset.data.category && asset.data.age_months !== undefined) { if (asset.data.age_months < 12) { asset.data.category = 'calf'; } else if (asset.data.gender === 'male' && asset.data.age_months < 24) { asset.data.category = 'steer'; } else if (asset.data.gender === 'male') { asset.data.category = 'bull'; } else if (asset.data.gender === 'female' && asset.data.age_months >= 24) { asset.data.category = 'cow'; } else { asset.data.category = 'heifer'; } } return asset; } private processPigs(asset: Asset): Asset { // Auto-calculate market readiness for finishing pigs if (asset.data.production_type === 'finishing' && asset.data.weight_kg) { asset.data.market_ready = asset.data.weight_kg >= 100 && asset.data.weight_kg <= 130; } return asset; } private processChickens(asset: Asset): Asset { // Calculate production metrics for layers if (asset.data.production_type === 'layer' && asset.data.eggs_per_day && asset.data.flock_size) { asset.data.laying_percentage = (asset.data.eggs_per_day / asset.data.flock_size) * 100; } return asset; } // Optional: Override hooks for livestock-specific needs async beforeProcess(asset: Asset): Promise<Asset> { // Example: Normalize breed names if (asset.data.breed) { asset.data.breed = asset.data.breed.toLowerCase().trim(); } return asset; } async afterProcess(asset: Asset): Promise<Asset> { // Example: Add quality score based on various factors let qualityScore = 100; if (!asset.data.vaccination_status || asset.data.vaccination_status === 'unknown') { qualityScore -= 20; } if (asset.data.health_status !== 'healthy') { qualityScore -= 30; } if (!asset.data.ear_tag && !asset.data.rfid) { qualityScore -= 10; } asset.data.quality_score = Math.max(0, qualityScore); return asset; } }