Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions .drone.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
{
"kind": "pipeline",
"name": "python:3.7,django>=3.1,<3.2",
"name": "python:3.10,django>=4.2,<4.3",
"platform": {
"arch": "amd64",
"os": "linux"
Expand All @@ -19,7 +19,7 @@
"MYSQL_ROOT_PASSWORD": "secret",
"MYSQL_USER": "silver"
},
"image": "mysql:5.7",
"image": "mysql:8.0",
"name": "mysql",
"pull": "if-not-exists"
},
Expand All @@ -33,15 +33,15 @@
{
"commands": [
"make dependencies",
"pip install -U \"Django>=3.1,<3.2\"",
"pip install -U \"django>=4.2,<4.3\"",
"mkdir /var/log/silver",
"make lint",
"make test"
],
"environment": {
"SILVER_DB_URL": "mysql://silver:silver@mysql/db"
},
"image": "python:3.7",
"image": "python:3.10",
"name": "test",
"pull": "always",
"settings": {
Expand Down Expand Up @@ -105,7 +105,7 @@
---
{
"kind": "pipeline",
"name": "python:3.8,django>=3.1,<3.2",
"name": "python:3.11,django>=4.2,<4.3",
"platform": {
"arch": "amd64",
"os": "linux"
Expand All @@ -123,7 +123,7 @@
"MYSQL_ROOT_PASSWORD": "secret",
"MYSQL_USER": "silver"
},
"image": "mysql:5.7",
"image": "mysql:8.0",
"name": "mysql",
"pull": "if-not-exists"
},
Expand All @@ -137,15 +137,15 @@
{
"commands": [
"make dependencies",
"pip install -U \"Django>=3.1,<3.2\"",
"pip install -U \"django>=4.2,<4.3\"",
"mkdir /var/log/silver",
"make lint",
"make test"
],
"environment": {
"SILVER_DB_URL": "mysql://silver:silver@mysql/db"
},
"image": "python:3.8",
"image": "python:3.11",
"name": "test",
"pull": "always",
"settings": {
Expand Down Expand Up @@ -209,7 +209,7 @@
---
{
"kind": "pipeline",
"name": "python:3.7,django>=3.2,<3.3",
"name": "python:3.10,django>=3.2,<3.3",
"platform": {
"arch": "amd64",
"os": "linux"
Expand All @@ -227,7 +227,7 @@
"MYSQL_ROOT_PASSWORD": "secret",
"MYSQL_USER": "silver"
},
"image": "mysql:5.7",
"image": "mysql:8.0",
"name": "mysql",
"pull": "if-not-exists"
},
Expand All @@ -249,7 +249,7 @@
"environment": {
"SILVER_DB_URL": "mysql://silver:silver@mysql/db"
},
"image": "python:3.7",
"image": "python:3.10",
"name": "test",
"pull": "always",
"settings": {
Expand Down Expand Up @@ -313,7 +313,7 @@
---
{
"kind": "pipeline",
"name": "python:3.8,django>=3.2,<3.3",
"name": "python:3.11,django>=3.2,<3.3",
"platform": {
"arch": "amd64",
"os": "linux"
Expand All @@ -331,7 +331,7 @@
"MYSQL_ROOT_PASSWORD": "secret",
"MYSQL_USER": "silver"
},
"image": "mysql:5.7",
"image": "mysql:8.0",
"name": "mysql",
"pull": "if-not-exists"
},
Expand All @@ -353,7 +353,7 @@
"environment": {
"SILVER_DB_URL": "mysql://silver:silver@mysql/db"
},
"image": "python:3.8",
"image": "python:3.11",
"name": "test",
"pull": "always",
"settings": {
Expand Down Expand Up @@ -416,6 +416,6 @@
}
---
kind: signature
hmac: beee66896031cb6802633da0a02d083cff16b93f6787729fd5d58b5710e543e0
hmac: 1231c01a60b201851df1d8bb5856897afcbde610438a08a84aa6321a58e7452a

...
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.9-alpine
FROM python:3.11-alpine
MAINTAINER Presslabs ping@presslabs.com

# Ensure that Python outputs everything that's printed inside
Expand Down
18 changes: 9 additions & 9 deletions requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@
# UNMAINTAINED means the package owner is no longer maintaining it

# Core
Django>=3.1,<3.3 # ------------------------------------------------------------ (bumped 2021-06-24)
Django>=3.2,<5.0 # ------------------------------------------------------------ (bumped 2023-09-18)
sqlparse>=0.2,<0.5 # (required for some old migrations) ----------------------- (bumped 2021-04-15)

# Django Utils
django-fsm>=2.7,<2.8 # -------------------------------------------------------- (bumped 2021-04-15)
django-filter>=2.4,<2.5 # ----------------------------------------------------- (bumped 2021-04-15)
django-livefield>=3.3,<3.4 # -------------------------------------------------- (bumped 2021-04-15)
django-model-utils>=4.1,<4.2 # ------------------------------------------------ (bumped 2021-04-15)
django-livefield>=4.0,<4.1 # -------------------------------------------------- (bumped 2023-12-18)
django-model-utils>=4.3.1,<4.4 # ---------------------------------------------- (bumped 2023-09-18)
django-annoying>=0.10,<0.11 # (various Django helpers) ----------------------- (checked 2021-04-15)
django-autocomplete-light>=3.8,<3.9 # ----------------------------------------- (bumped 2021-04-15)
django-autocomplete-light>=3.9.7,<3.10 # -------------------------------------- (bumped 2023-09-18)

# API
djangorestframework>=3.12,<3.13 # --------------------------------------------- (bumped 2021-04-15)
djangorestframework>=3.14,<3.15 # --------------------------------------------- (bumped 2023-09-18)
djangorestframework-bulk<0.3 # ----------------------------------------------- (checked 2021-04-15)

# I18n
pycountry>=20.7.3 # ----------------------------------------------------------- (bumped 2021-04-15)
python-dateutil>=2.8,<2.9 # --------------------------------------------------- (bumped 2021-04-15)
pycountry>=22.3.5 # ----------------------------------------------------------- (bumped 2023-09-18)
python-dateutil>=2.8,<2.9 # -------------------------------------------------- (checked 2023-09-18)
pyvat>=1.3,<1.4 # ------------------------------------------------------------ (checked 2021-04-15)

# Crypto
cryptography>=3.3,<3.4 # ------------------------------------------------------ (bumped 2021-04-15)
PyJWT>=2.0,<2.1 # ------------------------------------------------------------- (bumped 2021-04-15)
cryptography>=41.0.3,<42.0 # -------------------------------------------------- (bumped 2023-09-18)
PyJWT>=2.8,<2.9 # ------------------------------------------------------------- (bumped 2023-09-18)

# Other
furl>=1.2,<1.3 # (URL parsing and manipulation) NOT_LATEST -------------------- (bumped 2018-08-10)
Expand Down
4 changes: 2 additions & 2 deletions requirements/optionals.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
celery>=4.0,<5.1 # ------------------------------------------------------------ (bumped 2021-04-15)
redis>=2.10,<2.11 # ----------------------------------------------------------- (bumped 2018-06-07)
celery>=5.3.4,<5.4 # ---------------------------------------------------------- (bumped 2023-09-18)
redis>=5,<5.1 # --------------------------------------------------------------- (bumped 2023-09-18)
celery-once>=1.2,<3.1 # ------------------------------------------------------- (bumped 2021-04-15)
2 changes: 1 addition & 1 deletion requirements/test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ factory-boy==3.2.0
pep8==1.7.1
faker==8.2.1
django-environ==0.7
PyMySQL==1.0.2
PyMySQL==1.1.0
7 changes: 4 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,12 @@ def read(fname):
entry_points={"pytest11": ["django-silver = silver.fixtures.pytest_fixtures"]},
classifiers=[
'Environment :: Web Environment',
'Framework :: Django :: 3.1',
'Framework :: Django :: 3.2',
'Framework :: Django :: 4.1',
'Framework :: Django :: 4.2',
'Development Status :: 5 - Production/Stable',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8'
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11'
]
)
2 changes: 1 addition & 1 deletion silver/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from __future__ import absolute_import

from django.conf.urls import re_path
from django.urls import re_path

from silver import views as silver_views
from silver.api.views import billing_entities_views, documents_views, payment_method_views, \
Expand Down
43 changes: 39 additions & 4 deletions silver/documents_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def generate(self, subscription=None, billing_date=None, customers=None,
:param customers: the customers for which one wants to generate the
proformas/invoices.
:param force_generate: if True, invoices are generated at the date
indicated by `billing_date` instead of the normal end of billing
indicated by `billing_date` instead of after the normal end of billing
cycle.

:note
Expand Down Expand Up @@ -114,7 +114,16 @@ def get_subscriptions_prepared_for_billing(self, customer, billing_date, force_g
criteria = {'state__in': [Subscription.STATES.ACTIVE,
Subscription.STATES.CANCELED]}
for subscription in customer.subscriptions.filter(**criteria):
if subscription.should_be_billed(billing_date) or force_generate:
to_bill = subscription.should_be_billed(billing_date) or force_generate

if not to_bill and subscription.cancel_date:
billing_up_to_dates = subscription.billed_up_to_dates
to_bill = (
subscription.cancel_date < billing_up_to_dates["metered_features_billed_up_to"] and
subscription.cancel_date < billing_up_to_dates["plan_billed_up_to"]
)

if to_bill:
subs_to_bill.append(subscription)

return subs_to_bill
Expand All @@ -135,7 +144,6 @@ def _bill_subscription_into_document(self, subscription, billing_date, document=
})

billing_log, entries_info = self.add_subscription_cycles_to_document(**kwargs)

if subscription.state == Subscription.STATES.CANCELED:
subscription.end()
subscription.save()
Expand Down Expand Up @@ -382,6 +390,12 @@ def _generate_for_user_with_consolidated_billing(self, customer, billing_date, f

self._create_discount_entries(**kwargs)

# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
# should be refactored.
if not document.entries.exists():
document.delete()
continue

if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:
document.issue()

Expand All @@ -405,6 +419,12 @@ def _generate_for_user_without_consolidated_billing(self, customer, billing_date

self._create_discount_entries(**kwargs)

# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
# should be refactored.
if not document.entries.exists():
document.delete()
continue

if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:
document.issue()

Expand All @@ -419,14 +439,29 @@ def _generate_for_single_subscription(self, subscription=None, billing_date=None

provider = subscription.provider

if not subscription.should_be_billed(billing_date) or force_generate:
to_bill = subscription.should_be_billed(billing_date) or force_generate

if not to_bill and subscription.cancel_date:
billing_up_to_dates = subscription.billed_up_to_dates
to_bill = (
subscription.cancel_date < billing_up_to_dates["metered_features_billed_up_to"] and
subscription.cancel_date < billing_up_to_dates["plan_billed_up_to"]
)

if not to_bill:
return

document, discount_amounts = self._bill_subscription_into_document(subscription, billing_date)

kwargs = {'entries_info': discount_amounts,
provider.flow: document}

# TODO: Creating and then deleting the document in the DB is not ideal and this whole logic
# should be refactored.
if not document.entries.exists():
document.delete()
return

self._create_discount_entries(**kwargs)

if provider.default_document_state == Provider.DEFAULT_DOC_STATE.ISSUED:
Expand Down
15 changes: 10 additions & 5 deletions silver/management/commands/generate_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,35 @@ def add_arguments(self, parser):
parser.add_argument('--date',
action='store', dest='billing_date', type=date,
help='The billing date (format YYYY-MM-DD).')
parser.add_argument('--force',
action='store', dest='force_generate', type=bool,
help='Bill subscriptions even in situations when they would be skipped.')

def handle(self, *args, **options):
translation.activate('en-us')

billing_date = options['billing_date']
force_generate = options.get('force_generate', False)

docs_generator = DocumentsGenerator()
if options['subscription_id']:
try:
subscription_id = options['subscription_id']
logger.info('Generating for subscription with id=%s; '
'billing_date=%s.', subscription_id,
billing_date)
'billing_date=%s; force_generate=%s.', subscription_id,
billing_date, force_generate)

subscription = Subscription.objects.get(id=subscription_id)
docs_generator.generate(subscription=subscription,
billing_date=billing_date)
billing_date=billing_date,
force_generate=force_generate)
self.stdout.write('Done. You can have a Club-Mate now. :)')
except Subscription.DoesNotExist:
msg = 'The subscription with the provided id does not exist.'
self.stdout.write(msg)
else:
logger.info('Generating for all the available subscriptions; '
'billing_date=%s.', billing_date)
'billing_date=%s; force_generate=%s.', billing_date, force_generate)

docs_generator.generate(billing_date=billing_date)
docs_generator.generate(billing_date=billing_date, force_generate=force_generate)
self.stdout.write('Done. You can have a Club-Mate now. :)')
3 changes: 2 additions & 1 deletion silver/models/documents/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
from django.db import models

from silver.utils.decorators import require_transaction_currency_and_xe_rate
from silver.utils.models import AutoCleanModelMixin


class DocumentEntry(models.Model):
class DocumentEntry(AutoCleanModelMixin, models.Model):
description = models.TextField()
unit = models.CharField(max_length=1024, blank=True, null=True)
quantity = models.DecimalField(max_digits=19, decimal_places=4,
Expand Down
3 changes: 3 additions & 0 deletions silver/models/documents/invoice.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def __init__(self, *args, **kwargs):

@property
def transactions(self):
if not self.pk:
return self.invoice_transactions.model.objects.none()

return self.invoice_transactions.all()

@locking_atomic_transition(field='state', source=BillingDocumentBase.STATES.DRAFT,
Expand Down
3 changes: 3 additions & 0 deletions silver/models/documents/proforma.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def __init__(self, *args, **kwargs):

@property
def transactions(self):
if not self.pk:
return self.proforma_transactions.model.objects.none()

return self.proforma_transactions.all()

def clean(self):
Expand Down
Loading