From 557fdda9bcb8d687d21c4277dc63ca27dfa56771 Mon Sep 17 00:00:00 2001 From: Groupr Date: Tue, 2 Dec 2025 13:03:34 +0000 Subject: [PATCH] Update 3 files - /make_post_sell/models/paypal_payment.py - /make_post_sell/models/paypal_user_shop.py - /make_post_sell/models/__init__.py --- make_post_sell/models/__init__.py | 3 +- make_post_sell/models/paypal_payment.py | 75 +++++++++++++++++++++++ make_post_sell/models/paypal_user_shop.py | 55 +++++++++++++++++ 3 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 make_post_sell/models/paypal_payment.py create mode 100644 make_post_sell/models/paypal_user_shop.py diff --git a/make_post_sell/models/__init__.py b/make_post_sell/models/__init__.py index bca7d67..3e30291 100644 --- a/make_post_sell/models/__init__.py +++ b/make_post_sell/models/__init__.py @@ -27,7 +27,8 @@ from .user_crypto_refund_address import * from .stripe_user_shop import * from .paypal_payment import * -from .paypal_user_shop import * +from .paypal_user_shop import * + from .shop_search_request import * from .comment import * diff --git a/make_post_sell/models/paypal_payment.py b/make_post_sell/models/paypal_payment.py new file mode 100644 index 0000000..f6608c3 --- /dev/null +++ b/make_post_sell/models/paypal_payment.py @@ -0,0 +1,75 @@ +import uuid + +from sqlalchemy import Column, BigInteger, Unicode + +from .meta import Base, RBase, UUIDType, foreign_key, now_timestamp + +from sqlalchemy.orm import relationship, backref + + +class PayPalPayment(RBase, Base): + """ + Tracks PayPal payment transactions for invoices. + Stores PayPal order/payment IDs and status for each transaction. + """ + + id = Column(UUIDType, primary_key=True, index=True) + invoice_id = Column(UUIDType, foreign_key("Invoice", "id"), nullable=False) + + # PayPal order ID (e.g., "5O190127TN364715T") + paypal_order_id = Column(Unicode(64), nullable=False) + + # PayPal payer ID + paypal_payer_id = Column(Unicode(64), nullable=True) + + # PayPal capture ID (after order is captured) + paypal_capture_id = Column(Unicode(64), nullable=True) + + # Payment status: CREATED, APPROVED, VOIDED, COMPLETED, PAYER_ACTION_REQUIRED + status = Column(Unicode(32), nullable=False, default="CREATED") + + # Amount in cents + amount_in_cents = Column(BigInteger, nullable=False) + + created_timestamp = Column(BigInteger, nullable=False) + updated_timestamp = Column(BigInteger, nullable=False) + + invoice = relationship( + argument="Invoice", + backref=backref("paypal_payment", uselist=False, cascade="all, delete-orphan"), + ) + + def __init__(self, invoice=None): + self.id = uuid.uuid1() + self.invoice = invoice + self.created_timestamp = now_timestamp() + self.updated_timestamp = now_timestamp() + + @property + def is_completed(self): + """Check if payment is completed.""" + return self.status == "COMPLETED" + + @property + def is_pending(self): + """Check if payment is pending approval/capture.""" + return self.status in ["CREATED", "APPROVED", "PAYER_ACTION_REQUIRED"] + + @property + def is_failed(self): + """Check if payment failed or was voided.""" + return self.status == "VOIDED" + + def update_status(self, new_status): + """Update payment status and timestamp.""" + self.status = new_status + self.updated_timestamp = now_timestamp() + + +def get_paypal_payment_by_order_id(dbsession, paypal_order_id): + """Get PayPalPayment by PayPal order ID.""" + return ( + dbsession.query(PayPalPayment) + .filter(PayPalPayment.paypal_order_id == paypal_order_id) + .one_or_none() + ) diff --git a/make_post_sell/models/paypal_user_shop.py b/make_post_sell/models/paypal_user_shop.py new file mode 100644 index 0000000..500e625 --- /dev/null +++ b/make_post_sell/models/paypal_user_shop.py @@ -0,0 +1,55 @@ +import uuid + +from sqlalchemy import Column, Unicode + +from .meta import Base, RBase, UUIDType, foreign_key + +from sqlalchemy.orm import relationship, backref + + +class PayPalUserShop(RBase, Base): + """ + A user may have zero or many unique PayPal payer IDs for each shop it makes purchases on. + This tracks saved PayPal payment methods and customer relationships per shop. + """ + + id = Column(UUIDType, primary_key=True, index=True) + user_id = Column(UUIDType, foreign_key("User", "id"), nullable=False) + shop_id = Column(UUIDType, foreign_key("Shop", "id"), nullable=False) + + # PayPal payer ID (e.g., "PAYERID123ABC") + payer_id = Column(Unicode(64), nullable=True) + + # Billing agreement ID for reference transactions (optional) + billing_agreement_id = Column(Unicode(64), nullable=True) + + # Active payment token for saved payment methods (optional) + active_payment_token = Column(Unicode(128), nullable=True) + + user = relationship( + argument="User", backref=backref("paypal_user", cascade="all, delete-orphan") + ) + + shop = relationship( + argument="Shop", backref=backref("paypal_shop", cascade="all, delete-orphan") + ) + + def __init__(self, user=None, shop=None): + self.id = uuid.uuid1() + self.user = user + self.shop = shop + + @property + def has_billing_agreement(self): + """Check if this user has an active billing agreement with PayPal.""" + return self.billing_agreement_id is not None + + @property + def has_saved_payment_method(self): + """Check if this user has a saved payment token.""" + return self.active_payment_token is not None + + +def get_all_paypal_user_shop_objects(dbsession): + """Return all PayPalUserShop objects.""" + return dbsession.query(PayPalUserShop).all()