feat: anvil_transfer_pricing 동기화 로직 추가
- syncAnvilTransferPricing 메서드 구현 - 프로바이더별 도매 비용: Linode $0.005/GB, Vultr $0.01/GB, AWS $0.09/GB - 소매 가격 계산: cost × 1.21 (21% 마진) - Stage 8.5에서 자동 실행 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -377,6 +377,21 @@ export class SyncOrchestrator {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stage 8.5: Sync Anvil Transfer Pricing
|
||||||
|
let anvilTransferPricingCount = 0;
|
||||||
|
try {
|
||||||
|
anvilTransferPricingCount = await this.syncAnvilTransferPricing(provider);
|
||||||
|
if (anvilTransferPricingCount > 0) {
|
||||||
|
this.logger.info(`${provider} → SYNC_ANVIL_TRANSFER_PRICING`, { anvil_transfer_pricing: anvilTransferPricingCount });
|
||||||
|
}
|
||||||
|
} catch (transferError) {
|
||||||
|
// Log error but don't fail the entire sync
|
||||||
|
this.logger.error('Anvil transfer pricing sync failed', {
|
||||||
|
provider,
|
||||||
|
error: transferError instanceof Error ? transferError.message : String(transferError)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Stage 9: Complete - Update provider status to success
|
// Stage 9: Complete - Update provider status to success
|
||||||
stage = SyncStage.COMPLETE;
|
stage = SyncStage.COMPLETE;
|
||||||
await this.repos.providers.updateSyncStatus(provider, 'success');
|
await this.repos.providers.updateSyncStatus(provider, 'success');
|
||||||
@@ -1121,6 +1136,84 @@ export class SyncOrchestrator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Synchronize Anvil transfer pricing based on source provider
|
||||||
|
*
|
||||||
|
* Updates anvil_transfer_pricing table with retail transfer costs
|
||||||
|
* Formula: retail = cost × 1.21 (21% margin)
|
||||||
|
*
|
||||||
|
* Provider costs (per GB):
|
||||||
|
* - Linode: $0.005/GB
|
||||||
|
* - Vultr: $0.01/GB
|
||||||
|
* - AWS: $0.09/GB (Asia regions)
|
||||||
|
*
|
||||||
|
* @param provider - Source provider name (linode, vultr, aws)
|
||||||
|
* @returns Number of anvil_transfer_pricing records updated
|
||||||
|
*/
|
||||||
|
private async syncAnvilTransferPricing(provider: string): Promise<number> {
|
||||||
|
this.logger.info('Starting Anvil transfer pricing sync', { provider });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Step 1: Define provider costs per GB (wholesale)
|
||||||
|
const providerCosts: Record<string, number> = {
|
||||||
|
linode: 0.005, // $0.005/GB
|
||||||
|
vultr: 0.01, // $0.01/GB
|
||||||
|
aws: 0.09, // $0.09/GB (Asia regions)
|
||||||
|
};
|
||||||
|
|
||||||
|
const costPerGb = providerCosts[provider.toLowerCase()];
|
||||||
|
if (!costPerGb) {
|
||||||
|
this.logger.info('No transfer pricing defined for provider', { provider });
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 2: Find all anvil_regions sourced from this provider
|
||||||
|
const anvilRegionsResult = await this.repos.db
|
||||||
|
.prepare('SELECT id, source_region_id FROM anvil_regions WHERE source_provider = ?')
|
||||||
|
.bind(provider)
|
||||||
|
.all<{ id: number; source_region_id: number }>();
|
||||||
|
|
||||||
|
if (!anvilRegionsResult.success || anvilRegionsResult.results.length === 0) {
|
||||||
|
this.logger.info('No anvil_regions found for provider', { provider });
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const anvilRegions = anvilRegionsResult.results;
|
||||||
|
this.logger.info('Found anvil_regions for transfer pricing', {
|
||||||
|
provider,
|
||||||
|
count: anvilRegions.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 3: Calculate retail price (cost × 1.21 for 21% margin)
|
||||||
|
const retailPricePerGb = costPerGb * 1.21;
|
||||||
|
|
||||||
|
// Step 4: Prepare upsert data for all regions
|
||||||
|
const transferPricingData = anvilRegions.map(region => ({
|
||||||
|
anvil_region_id: region.id,
|
||||||
|
price_per_gb: retailPricePerGb,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Step 5: Batch upsert using repository
|
||||||
|
const upsertCount = await this.repos.anvilTransferPricing.upsertMany(transferPricingData);
|
||||||
|
|
||||||
|
this.logger.info('Anvil transfer pricing sync completed', {
|
||||||
|
provider,
|
||||||
|
cost_per_gb: costPerGb,
|
||||||
|
retail_price_per_gb: retailPricePerGb,
|
||||||
|
regions_updated: upsertCount,
|
||||||
|
});
|
||||||
|
|
||||||
|
return upsertCount;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('Anvil transfer pricing sync failed', {
|
||||||
|
provider,
|
||||||
|
error: error instanceof Error ? error.message : String(error)
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create connector for a specific provider
|
* Create connector for a specific provider
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user