Skip to main content

syrup_rail_postgres/
operator_review.rs

1use std::{error::Error, fmt};
2
3use async_trait::async_trait;
4use chrono::{DateTime, Utc};
5use sqlx::{PgConnection, PgPool, Postgres, Row, Transaction, postgres::PgRow};
6use syrup_rail::{
7    ActorId, AttemptReviewCursor, AttemptReviewPage, BillingEventSubject, BillingScopeId,
8    CurrencyCode, ExternalReversalAttestation, ExternalReversalHostChargeRelease,
9    ExternalReversalKind, ExternalReversalReason, GatewayAccountId, GatewayDiagnostic,
10    GatewayOrderId, GatewayPaymentDescriptor, GatewayPaymentMethodReference, GatewayTransactionId,
11    HostChargeTargetId, ManualAttemptFailureOutcome, ManualFailureHostCharge, Money,
12    OperatorReviewPageLimit, PaymentAttempt, PaymentAttemptId, PaymentAttemptKind,
13    PaymentAttemptStatus, PaymentResolutionCode, PlanKey, ProcessorCharge, ProcessorChargeId,
14    ProcessorChargeProgression, ProcessorChargeReviewCursor, ProcessorChargeReviewItem,
15    ProcessorChargeReviewPage, ProcessorChargeRole, ProcessorEvidence, SubscriberId,
16    review_required_attempt_can_be_manually_failed, review_required_manual_failure_evidence,
17};
18use thiserror::Error;
19use uuid::Uuid;
20
21#[cfg(test)]
22use syrup_rail::BillingEvent;
23
24use crate::attempts::{
25    lock_payment_attempt_by_id_on_connection, lock_subscription_aggregate,
26    payment_attempt_from_row, set_enrollment_timeouts,
27};
28use crate::host_error::{BoxError, RedactedHostErrorSource};
29use crate::processor_charge_persistence::{
30    attestation_by_charge, attestation_matches_source, expected_final_resolution_code,
31    expected_prior_resolution_code, parse_charge_state_code, parse_kind, parse_progression,
32    parse_role, processor_charge_from_row,
33};
34use crate::renewal_failure::{
35    RenewalFailureApplication, RenewalFailureStoreError, apply_resolved_automatic_renewal_failure,
36};
37use crate::transactions::{
38    BillingEventWriteError, BillingTransactionCoordinator, BillingTransactionError,
39};
40
41mod external_reversal;
42mod manual_failure;
43mod pages;
44
45pub use external_reversal::{
46    ExternalReversalAttestationOutcome, ExternalReversalHostStore, ExternalReversalHostStoreError,
47    ExternalReversalHostTransitionOutcome, attest_external_reversal,
48};
49pub use manual_failure::{
50    ManualAttemptFailureHostStore, ManualAttemptFailureHostStoreError,
51    ManualAttemptFailureHostTransitionOutcome, fail_review_required_attempt,
52};
53pub use pages::{attempt_review_page, processor_charge_review_page};
54
55#[cfg(test)]
56use external_reversal::{charge_locator, lock_processor_charge};
57
58pub(crate) const INVALID_OPERATOR_STATE: &str = "canonical operator review state is invalid";
59
60#[derive(Debug, Error)]
61pub enum OperatorReviewError {
62    #[error("operator review storage operation failed")]
63    Sql(#[from] sqlx::Error),
64    #[error("{0}")]
65    InvalidState(&'static str),
66    #[error(transparent)]
67    Host(#[from] ExternalReversalHostStoreError),
68    #[error(transparent)]
69    ManualFailureHost(#[from] ManualAttemptFailureHostStoreError),
70    #[error(transparent)]
71    BillingTransaction(#[from] BillingTransactionError),
72    #[error(transparent)]
73    BillingEvent(#[from] BillingEventWriteError),
74}
75
76impl From<crate::PaymentAttemptStoreError> for OperatorReviewError {
77    fn from(error: crate::PaymentAttemptStoreError) -> Self {
78        match error {
79            crate::PaymentAttemptStoreError::Sql(error) => Self::Sql(error),
80            crate::PaymentAttemptStoreError::InvalidState(_) => {
81                Self::InvalidState(INVALID_OPERATOR_STATE)
82            }
83        }
84    }
85}
86
87impl From<RenewalFailureStoreError> for OperatorReviewError {
88    fn from(error: RenewalFailureStoreError) -> Self {
89        match error {
90            RenewalFailureStoreError::Sql(error) => Self::Sql(error),
91            RenewalFailureStoreError::Attempt(error) => error.into(),
92            RenewalFailureStoreError::InvalidState(_) => Self::InvalidState(INVALID_OPERATOR_STATE),
93        }
94    }
95}
96
97#[cfg(test)]
98mod tests;