use std::io::Read;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SalesReportRow {
#[serde(rename = "Provider")]
pub provider: String,
#[serde(rename = "Provider Country")]
pub provider_country: String,
#[serde(rename = "SKU")]
pub sku: String,
#[serde(rename = "Developer")]
pub developer: String,
#[serde(rename = "Title")]
pub title: String,
#[serde(rename = "Version")]
pub version: String,
#[serde(rename = "Product Type Identifier")]
pub product_type_identifier: String,
#[serde(rename = "Units")]
pub units: String,
#[serde(rename = "Developer Proceeds")]
pub developer_proceeds: String,
#[serde(rename = "Currency of Proceeds")]
pub currency_of_proceeds: String,
#[serde(rename = "Begin Date")]
pub begin_date: String,
#[serde(rename = "End Date")]
pub end_date: String,
#[serde(rename = "Customer Currency")]
pub customer_currency: String,
#[serde(rename = "Customer Price")]
pub customer_price: String,
#[serde(rename = "Promo Code")]
pub promo_code: String,
#[serde(rename = "Parent Identifier")]
pub parent_identifier: String,
#[serde(rename = "Subscription")]
pub subscription: String,
#[serde(rename = "Period")]
pub period: String,
#[serde(rename = "Category")]
pub category: String,
#[serde(rename = "CMB")]
pub cmb: String,
#[serde(rename = "Device")]
pub device: String,
#[serde(rename = "Supported Platforms")]
pub supported_platforms: String,
#[serde(rename = "Proceeds Reason")]
pub proceeds_reason: String,
#[serde(rename = "Preserved Pricing")]
pub preserved_pricing: String,
#[serde(rename = "Client")]
pub client: String,
#[serde(rename = "Order Type")]
pub order_type: String,
}
pub fn parse_sales_tsv(data: &[u8]) -> Result<Vec<SalesReportRow>, SalesTsvError> {
let mut decoder = flate2::read::GzDecoder::new(data);
let mut decompressed = Vec::new();
decoder
.read_to_end(&mut decompressed)
.map_err(|e| SalesTsvError::Decompression(e.to_string()))?;
let mut reader = csv::ReaderBuilder::new()
.delimiter(b'\t')
.flexible(true)
.from_reader(decompressed.as_slice());
let mut rows = Vec::new();
for result in reader.deserialize() {
let row: SalesReportRow = result.map_err(|e| SalesTsvError::Parse(e.to_string()))?;
rows.push(row);
}
Ok(rows)
}
#[derive(Debug, thiserror::Error)]
pub enum SalesTsvError {
#[error("gzip decompression failed: {0}")]
Decompression(String),
#[error("TSV parse error: {0}")]
Parse(String),
}
#[cfg(test)]
#[path = "sales_tests.rs"]
mod tests;