You've already forked AstralRinth
forked from didirus/AstralRinth
Charge tax on products (#4361)
* Initial Anrok integration * Query cache, fmt, clippy * Fmt * Use payment intent function in edit_subscription * Attach Anrok client, use payments in index_billing * Integrate Anrok with refunds * Bug fixes * More bugfixes * Fix resubscriptions * Medal promotion bugfixes * Use stripe metadata constants everywhere * Pre-fill values in products_tax_identifiers * Cleanup billing route module * Cleanup * Email notification for tax charge * Don't charge tax on users which haven't been notified of tax change * Fix taxnotification.amount templates * Update .env.docker-compose * Update .env.local * Clippy * Fmt * Query cache * Periodically update tax amount on upcoming charges * Fix queries * Skip indexing tax amount on charges if no charges to process * chore: query cache, clippy, fmt * Fix a lot of things * Remove test code * chore: query cache, clippy, fmt * Fix money formatting * Fix conflicts * Extra documentation, handle tax association properly * Track loss in tax drift * chore: query cache, clippy, fmt * Add subscription.id variable * chore: query cache, clippy, fmt * chore: query cache, clippy, fmt
This commit is contained in:
committed by
GitHub
parent
47020f34b6
commit
4228a193e9
@@ -1,7 +1,9 @@
|
||||
use crate::models::ids::{ThreadMessageId, VersionId};
|
||||
use crate::models::v3::billing::PriceDuration;
|
||||
use crate::models::{
|
||||
ids::{
|
||||
NotificationId, OrganizationId, ProjectId, ReportId, TeamId, ThreadId,
|
||||
UserSubscriptionId,
|
||||
},
|
||||
notifications::{Notification, NotificationAction, NotificationBody},
|
||||
projects::ProjectStatus,
|
||||
@@ -37,6 +39,17 @@ pub struct LegacyNotificationAction {
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(tag = "type", rename_all = "snake_case")]
|
||||
pub enum LegacyNotificationBody {
|
||||
TaxNotification {
|
||||
subscription_id: UserSubscriptionId,
|
||||
old_amount: i64,
|
||||
old_tax_amount: i64,
|
||||
new_amount: i64,
|
||||
new_tax_amount: i64,
|
||||
billing_interval: PriceDuration,
|
||||
currency: String,
|
||||
due: DateTime<Utc>,
|
||||
service: String,
|
||||
},
|
||||
ProjectUpdate {
|
||||
project_id: ProjectId,
|
||||
version_id: VersionId,
|
||||
@@ -198,6 +211,9 @@ impl LegacyNotification {
|
||||
NotificationBody::PaymentFailed { .. } => {
|
||||
Some("payment_failed".to_string())
|
||||
}
|
||||
NotificationBody::TaxNotification { .. } => {
|
||||
Some("tax_notification".to_string())
|
||||
}
|
||||
NotificationBody::PayoutAvailable { .. } => {
|
||||
Some("payout_available".to_string())
|
||||
}
|
||||
@@ -341,6 +357,27 @@ impl LegacyNotification {
|
||||
new_email,
|
||||
to_email,
|
||||
},
|
||||
NotificationBody::TaxNotification {
|
||||
subscription_id,
|
||||
old_amount,
|
||||
old_tax_amount,
|
||||
new_amount,
|
||||
new_tax_amount,
|
||||
billing_interval,
|
||||
currency,
|
||||
due,
|
||||
service,
|
||||
} => LegacyNotificationBody::TaxNotification {
|
||||
subscription_id,
|
||||
old_amount,
|
||||
old_tax_amount,
|
||||
new_amount,
|
||||
new_tax_amount,
|
||||
billing_interval,
|
||||
due,
|
||||
service,
|
||||
currency,
|
||||
},
|
||||
NotificationBody::PaymentFailed { amount, service } => {
|
||||
LegacyNotificationBody::PaymentFailed { amount, service }
|
||||
}
|
||||
|
||||
@@ -66,6 +66,15 @@ pub enum Price {
|
||||
},
|
||||
}
|
||||
|
||||
impl Price {
|
||||
pub fn get_interval(&self, interval: PriceDuration) -> Option<i32> {
|
||||
match self {
|
||||
Price::OneTime { .. } => None,
|
||||
Price::Recurring { intervals } => intervals.get(&interval).copied(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Hash, Eq, PartialEq, Debug, Copy, Clone)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum PriceDuration {
|
||||
@@ -175,6 +184,16 @@ pub enum SubscriptionMetadata {
|
||||
Medal { id: String },
|
||||
}
|
||||
|
||||
impl SubscriptionMetadata {
|
||||
pub fn is_medal(&self) -> bool {
|
||||
matches!(self, SubscriptionMetadata::Medal { .. })
|
||||
}
|
||||
|
||||
pub fn is_pyro(&self) -> bool {
|
||||
matches!(self, SubscriptionMetadata::Pyro { .. })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Charge {
|
||||
pub id: ChargeId,
|
||||
|
||||
@@ -2,6 +2,7 @@ use super::ids::*;
|
||||
use crate::database::models::notification_item::DBNotification;
|
||||
use crate::database::models::notification_item::DBNotificationAction;
|
||||
use crate::database::models::notifications_deliveries_item::DBNotificationDelivery;
|
||||
use crate::models::billing::PriceDuration;
|
||||
use crate::models::ids::{
|
||||
NotificationId, ProjectId, ReportId, TeamId, ThreadId, ThreadMessageId,
|
||||
VersionId,
|
||||
@@ -46,6 +47,7 @@ pub enum NotificationType {
|
||||
PasswordRemoved,
|
||||
EmailChanged,
|
||||
PaymentFailed,
|
||||
TaxNotification,
|
||||
PatCreated,
|
||||
ModerationMessageReceived,
|
||||
ReportStatusUpdated,
|
||||
@@ -76,7 +78,9 @@ impl NotificationType {
|
||||
NotificationType::PasswordRemoved => "password_removed",
|
||||
NotificationType::EmailChanged => "email_changed",
|
||||
NotificationType::PaymentFailed => "payment_failed",
|
||||
NotificationType::TaxNotification => "tax_notification",
|
||||
NotificationType::PatCreated => "pat_created",
|
||||
NotificationType::PayoutAvailable => "payout_available",
|
||||
NotificationType::ModerationMessageReceived => {
|
||||
"moderation_message_received"
|
||||
}
|
||||
@@ -87,7 +91,6 @@ impl NotificationType {
|
||||
}
|
||||
NotificationType::ProjectStatusNeutral => "project_status_neutral",
|
||||
NotificationType::ProjectTransferred => "project_transferred",
|
||||
NotificationType::PayoutAvailable => "payout_available",
|
||||
NotificationType::Unknown => "unknown",
|
||||
}
|
||||
}
|
||||
@@ -110,18 +113,7 @@ impl NotificationType {
|
||||
"password_removed" => NotificationType::PasswordRemoved,
|
||||
"email_changed" => NotificationType::EmailChanged,
|
||||
"payment_failed" => NotificationType::PaymentFailed,
|
||||
"pat_created" => NotificationType::PatCreated,
|
||||
"moderation_message_received" => {
|
||||
NotificationType::ModerationMessageReceived
|
||||
}
|
||||
"report_status_updated" => NotificationType::ReportStatusUpdated,
|
||||
"report_submitted" => NotificationType::ReportSubmitted,
|
||||
"project_status_approved" => {
|
||||
NotificationType::ProjectStatusApproved
|
||||
}
|
||||
"project_status_neutral" => NotificationType::ProjectStatusNeutral,
|
||||
"project_transferred" => NotificationType::ProjectTransferred,
|
||||
"payout_available" => NotificationType::PayoutAvailable,
|
||||
"tax_notification" => NotificationType::TaxNotification,
|
||||
"unknown" => NotificationType::Unknown,
|
||||
_ => NotificationType::Unknown,
|
||||
}
|
||||
@@ -218,6 +210,17 @@ pub enum NotificationBody {
|
||||
amount: String,
|
||||
service: String,
|
||||
},
|
||||
TaxNotification {
|
||||
subscription_id: UserSubscriptionId,
|
||||
new_amount: i64,
|
||||
new_tax_amount: i64,
|
||||
old_amount: i64,
|
||||
old_tax_amount: i64,
|
||||
billing_interval: PriceDuration,
|
||||
currency: String,
|
||||
due: DateTime<Utc>,
|
||||
service: String,
|
||||
},
|
||||
PayoutAvailable {
|
||||
date_available: DateTime<Utc>,
|
||||
amount: f64,
|
||||
@@ -293,6 +296,9 @@ impl NotificationBody {
|
||||
NotificationBody::PaymentFailed { .. } => {
|
||||
NotificationType::PaymentFailed
|
||||
}
|
||||
NotificationBody::TaxNotification { .. } => {
|
||||
NotificationType::TaxNotification
|
||||
}
|
||||
NotificationBody::PayoutAvailable { .. } => {
|
||||
NotificationType::PayoutAvailable
|
||||
}
|
||||
@@ -522,6 +528,12 @@ impl From<DBNotification> for Notification {
|
||||
"#".to_string(),
|
||||
vec![],
|
||||
),
|
||||
NotificationBody::TaxNotification { .. } => (
|
||||
"Tax notification".to_string(),
|
||||
"You've received a tax notification.".to_string(),
|
||||
"#".to_string(),
|
||||
vec![],
|
||||
),
|
||||
NotificationBody::PayoutAvailable { .. } => (
|
||||
"Payout available".to_string(),
|
||||
"A payout is available!".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user