Fixed mailer smtp connection reuse
This commit is contained in:
parent
120506229a
commit
3520b3968b
2
TODO.md
2
TODO.md
|
@ -434,5 +434,3 @@ serailzer self.instance on create.
|
||||||
* backendLog store method and language... and use it for display_script with correct lexer
|
* backendLog store method and language... and use it for display_script with correct lexer
|
||||||
|
|
||||||
# process monitor data to represent state, or maybe create new resource datas when period expires?
|
# process monitor data to represent state, or maybe create new resource datas when period expires?
|
||||||
|
|
||||||
# DNS when AAAA is specified include default A register?
|
|
||||||
|
|
|
@ -228,7 +228,8 @@ def amend_bills(modeladmin, request, queryset):
|
||||||
}
|
}
|
||||||
amend = Bill.objects.create(
|
amend = Bill.objects.create(
|
||||||
account=bill.account,
|
account=bill.account,
|
||||||
type=amend_type
|
type=amend_type,
|
||||||
|
amend_of=bill,
|
||||||
)
|
)
|
||||||
context['type'] = _(amend.get_type_display())
|
context['type'] = _(amend.get_type_display())
|
||||||
amend.comments = _("%(type)s of %(related_type)s %(number)s and creation date %(date)s") % context
|
amend.comments = _("%(type)s of %(related_type)s %(number)s and creation date %(date)s") % context
|
||||||
|
|
|
@ -22,9 +22,14 @@ from .models import Bill, Invoice, AmendmentInvoice, Fee, AmendmentFee, ProForma
|
||||||
|
|
||||||
|
|
||||||
PAYMENT_STATE_COLORS = {
|
PAYMENT_STATE_COLORS = {
|
||||||
|
Bill.OPEN: 'grey',
|
||||||
|
Bill.CREATED: 'darkorange',
|
||||||
|
Bill.PROCESSED: 'darkorange',
|
||||||
|
Bill.AMENDED: 'blue',
|
||||||
Bill.PAID: 'green',
|
Bill.PAID: 'green',
|
||||||
Bill.PENDING: 'darkorange',
|
Bill.EXECUTED: 'darkorange',
|
||||||
Bill.BAD_DEBT: 'red',
|
Bill.BAD_DEBT: 'red',
|
||||||
|
Bill.INCOMPLETE: 'red',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,10 +96,10 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
if self.value() == 'OPEN':
|
if self.value() == 'OPEN':
|
||||||
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
return queryset.filter(Q(is_open=True)|Q(type=queryset.model.PROFORMA))
|
||||||
elif self.value() == 'PAID':
|
elif self.value() == 'PAID':
|
||||||
zeros = queryset.filter(computed_total=0).values_list('id', flat=True)
|
zeros = queryset.filter(computed_total=0, computed_total__isnull=True).values_list('id', flat=True)
|
||||||
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
ammounts = Transaction.objects.exclude(bill_id__in=zeros).secured().group_by('bill_id')
|
||||||
paid = []
|
paid = []
|
||||||
for bill_id, total in queryset.exclude(computed_total=0).values_list('id', 'computed_total'):
|
for bill_id, total in queryset.exclude(computed_total=0, computed_total__isnull=True, is_open=True).values_list('id', 'computed_total'):
|
||||||
try:
|
try:
|
||||||
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
ammount = sum([t.ammount for t in ammounts[bill_id]])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -107,13 +107,12 @@ class PaymentStateListFilter(SimpleListFilter):
|
||||||
else:
|
else:
|
||||||
if abs(total) <= abs(ammount):
|
if abs(total) <= abs(ammount):
|
||||||
paid.append(bill_id)
|
paid.append(bill_id)
|
||||||
return queryset.filter(Q(computed_total=0)|Q(id__in=paid))
|
return queryset.filter(Q(computed_total=0)|Q(computed_total__isnull=True)|Q(id__in=paid)).exclude(is_open=True)
|
||||||
elif self.value() == 'PENDING':
|
elif self.value() == 'PENDING':
|
||||||
has_transaction = queryset.exclude(transactions__isnull=True)
|
has_transaction = queryset.exclude(transactions__isnull=True)
|
||||||
non_rejected = has_transaction.exclude(transactions__state=Transaction.REJECTED)
|
non_rejected = has_transaction.exclude(transactions__state=Transaction.REJECTED)
|
||||||
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
||||||
return queryset.filter(pk__in=non_rejected)
|
return queryset.filter(pk__in=non_rejected)
|
||||||
elif self.value() == 'BAD_DEBT':
|
elif self.value() == 'BAD_DEBT':
|
||||||
non_rejected = queryset.exclude(transactions__state=Transaction.REJECTED)
|
closed = queryset.filter(is_open=False).exclude(computed_total=0)
|
||||||
non_rejected = non_rejected.values_list('id', flat=True).distinct()
|
return closed.filter(Q(transactions__state=Transaction.REJECTED)|Q(transactions__isnull=True))
|
||||||
return queryset.exclude(pk__in=non_rejected)
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -64,15 +64,17 @@ class Bill(models.Model):
|
||||||
PROCESSED = 'PROCESSED'
|
PROCESSED = 'PROCESSED'
|
||||||
AMENDED = 'AMENDED'
|
AMENDED = 'AMENDED'
|
||||||
PAID = 'PAID'
|
PAID = 'PAID'
|
||||||
PENDING = 'PENDING'
|
EXECUTED = 'EXECUTED'
|
||||||
BAD_DEBT = 'BAD_DEBT'
|
BAD_DEBT = 'BAD_DEBT'
|
||||||
|
INCOMPLETE = 'INCOMPLETE'
|
||||||
PAYMENT_STATES = (
|
PAYMENT_STATES = (
|
||||||
(OPEN, _("Open")),
|
(OPEN, _("Open")),
|
||||||
(CREATED, _("Created")),
|
(CREATED, _("Created")),
|
||||||
(PROCESSED, _("Processed")),
|
(PROCESSED, _("Processed")),
|
||||||
(AMENDED, _("Amended")),
|
(AMENDED, _("Amended")),
|
||||||
(PAID, _("Paid")),
|
(PAID, _("Paid")),
|
||||||
(PENDING, _("Pending")),
|
(INCOMPLETE, _('Incomplete')),
|
||||||
|
(EXECUTED, _("Executed")),
|
||||||
(BAD_DEBT, _("Bad debt")),
|
(BAD_DEBT, _("Bad debt")),
|
||||||
)
|
)
|
||||||
BILL = 'BILL'
|
BILL = 'BILL'
|
||||||
|
@ -92,7 +94,8 @@ class Bill(models.Model):
|
||||||
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
|
number = models.CharField(_("number"), max_length=16, unique=True, blank=True)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("account"),
|
||||||
related_name='%(class)s')
|
related_name='%(class)s')
|
||||||
# amend_of = models.ForeignKey('self', null=True, blank=True, verbose_name=_("amend of"), related_name='amends')
|
amend_of = models.ForeignKey('self', null=True, blank=True, verbose_name=_("amend of"),
|
||||||
|
related_name='amends')
|
||||||
type = models.CharField(_("type"), max_length=16, choices=TYPES)
|
type = models.CharField(_("type"), max_length=16, choices=TYPES)
|
||||||
created_on = models.DateField(_("created on"), auto_now_add=True)
|
created_on = models.DateField(_("created on"), auto_now_add=True)
|
||||||
closed_on = models.DateField(_("closed on"), blank=True, null=True)
|
closed_on = models.DateField(_("closed on"), blank=True, null=True)
|
||||||
|
@ -133,14 +136,49 @@ class Bill(models.Model):
|
||||||
def payment_state(self):
|
def payment_state(self):
|
||||||
if self.is_open or self.get_type() == self.PROFORMA:
|
if self.is_open or self.get_type() == self.PROFORMA:
|
||||||
return self.OPEN
|
return self.OPEN
|
||||||
# elif self.amends.filter(is_open=False).exists():
|
elif self.amends.filter(is_open=False).exists():
|
||||||
# return self.AMENDED
|
return self.AMENDED
|
||||||
# TODO optimize this with a single query
|
secured = 0
|
||||||
secured = self.transactions.secured().amount() or 0
|
pending = 0
|
||||||
if abs(secured) >= abs(self.get_total()):
|
created = False
|
||||||
|
processed = False
|
||||||
|
executed = False
|
||||||
|
rejected = False
|
||||||
|
for transaction in self.transactions.all():
|
||||||
|
if transaction.state == transaction.SECURED:
|
||||||
|
secured += transaction.amount
|
||||||
|
pending += transaction.amount
|
||||||
|
elif transaction.state == transaction.WAITTING_PROCESSING:
|
||||||
|
pending += transaction.amount
|
||||||
|
created = True
|
||||||
|
elif transaction.state == transaction.WAITTING_EXECUTION:
|
||||||
|
pending += transaction.amount
|
||||||
|
processed = True
|
||||||
|
elif transaction.state == transaction.EXECUTED:
|
||||||
|
pending += transaction.amount
|
||||||
|
executed = True
|
||||||
|
elif transaction.state == transaction.REJECTED:
|
||||||
|
rejected = True
|
||||||
|
else:
|
||||||
|
raise TypeError("Unknown state")
|
||||||
|
ongoing = bool(secured != 0 or created or processed or executed)
|
||||||
|
total = self.get_total()
|
||||||
|
if total >= 0:
|
||||||
|
if secured >= total:
|
||||||
return self.PAID
|
return self.PAID
|
||||||
elif self.transactions.exclude_rejected().exists():
|
elif ongoing and pending < total:
|
||||||
return self.PENDING
|
return self.INCOMPLETE
|
||||||
|
else:
|
||||||
|
if secured <= total:
|
||||||
|
return self.PAID
|
||||||
|
elif ongoing and pending > total:
|
||||||
|
return self.INCOMPLETE
|
||||||
|
if created:
|
||||||
|
return self.CREATED
|
||||||
|
elif processed:
|
||||||
|
return self.PROCESSED
|
||||||
|
elif executed:
|
||||||
|
return self.EXECUTED
|
||||||
return self.BAD_DEBT
|
return self.BAD_DEBT
|
||||||
|
|
||||||
def get_total(self):
|
def get_total(self):
|
||||||
|
|
|
@ -172,13 +172,14 @@ class Domain(models.Model):
|
||||||
type=Record.MX,
|
type=Record.MX,
|
||||||
value=mx
|
value=mx
|
||||||
))
|
))
|
||||||
if not has_a and not has_aaaa:
|
if not has_a:
|
||||||
default_a = settings.DOMAINS_DEFAULT_A
|
default_a = settings.DOMAINS_DEFAULT_A
|
||||||
if default_a:
|
if default_a:
|
||||||
records.append(AttrDict(
|
records.append(AttrDict(
|
||||||
type=Record.A,
|
type=Record.A,
|
||||||
value=default_a
|
value=default_a
|
||||||
))
|
))
|
||||||
|
if not has_aaaa:
|
||||||
default_aaaa = settings.DOMAINS_DEFAULT_AAAA
|
default_aaaa = settings.DOMAINS_DEFAULT_AAAA
|
||||||
if default_aaaa:
|
if default_aaaa:
|
||||||
records.append(AttrDict(
|
records.append(AttrDict(
|
||||||
|
|
|
@ -25,7 +25,8 @@ def send_message(message, num=0, connection=None, bulk=settings.MAILER_BULK_MESS
|
||||||
error = None
|
error = None
|
||||||
try:
|
try:
|
||||||
connection.connection.sendmail(message.from_address, [message.to_address], smart_str(message.content))
|
connection.connection.sendmail(message.from_address, [message.to_address], smart_str(message.content))
|
||||||
except (SocketError, smtplib.SMTPSenderRefused,
|
except (SocketError,
|
||||||
|
smtplib.SMTPSenderRefused,
|
||||||
smtplib.SMTPRecipientsRefused,
|
smtplib.SMTPRecipientsRefused,
|
||||||
smtplib.SMTPAuthenticationError) as err:
|
smtplib.SMTPAuthenticationError) as err:
|
||||||
message.defer()
|
message.defer()
|
||||||
|
@ -33,6 +34,7 @@ def send_message(message, num=0, connection=None, bulk=settings.MAILER_BULK_MESS
|
||||||
else:
|
else:
|
||||||
message.sent()
|
message.sent()
|
||||||
message.log(error)
|
message.log(error)
|
||||||
|
return connection
|
||||||
|
|
||||||
|
|
||||||
def send_pending(bulk=settings.MAILER_BULK_MESSAGES):
|
def send_pending(bulk=settings.MAILER_BULK_MESSAGES):
|
||||||
|
@ -41,7 +43,7 @@ def send_pending(bulk=settings.MAILER_BULK_MESSAGES):
|
||||||
connection = None
|
connection = None
|
||||||
num = 0
|
num = 0
|
||||||
for message in Message.objects.filter(state=Message.QUEUED).order_by('priority'):
|
for message in Message.objects.filter(state=Message.QUEUED).order_by('priority'):
|
||||||
send_message(message, num, connection, bulk)
|
connection = send_message(message, num, connection, bulk)
|
||||||
num += 1
|
num += 1
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
qs = Q()
|
qs = Q()
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
.highlight .hll { background-color: #ffffcc }
|
||||||
|
.highlight { background: #f8f8f8; }
|
||||||
|
.highlight .c { color: #408080; font-style: italic } /* Comment */
|
||||||
|
.highlight .err { border: 1px solid #FF0000 } /* Error */
|
||||||
|
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
|
||||||
|
.highlight .o { color: #666666 } /* Operator */
|
||||||
|
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
|
||||||
|
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||||
|
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
|
||||||
|
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
|
||||||
|
.highlight .gd { color: #A00000 } /* Generic.Deleted */
|
||||||
|
.highlight .ge { font-style: italic } /* Generic.Emph */
|
||||||
|
.highlight .gr { color: #FF0000 } /* Generic.Error */
|
||||||
|
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||||
|
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||||
|
.highlight .go { color: #808080 } /* Generic.Output */
|
||||||
|
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||||
|
.highlight .gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||||
|
.highlight .gt { color: #0040D0 } /* Generic.Traceback */
|
||||||
|
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
|
||||||
|
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
|
||||||
|
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
|
||||||
|
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
|
||||||
|
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
|
||||||
|
.highlight .kt { color: #B00040 } /* Keyword.Type */
|
||||||
|
.highlight .m { color: #666666 } /* Literal.Number */
|
||||||
|
.highlight .s { color: #BA2121 } /* Literal.String */
|
||||||
|
.highlight .na { color: #7D9029 } /* Name.Attribute */
|
||||||
|
.highlight .nb { color: #008000 } /* Name.Builtin */
|
||||||
|
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||||
|
.highlight .no { color: #880000 } /* Name.Constant */
|
||||||
|
.highlight .nd { color: #AA22FF } /* Name.Decorator */
|
||||||
|
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||||
|
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||||
|
.highlight .nf { color: #0000FF } /* Name.Function */
|
||||||
|
.highlight .nl { color: #A0A000 } /* Name.Label */
|
||||||
|
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||||
|
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
|
||||||
|
.highlight .nv { color: #19177C } /* Name.Variable */
|
||||||
|
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||||
|
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
|
||||||
|
.highlight .mf { color: #666666 } /* Literal.Number.Float */
|
||||||
|
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
|
||||||
|
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
|
||||||
|
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
|
||||||
|
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
|
||||||
|
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
|
||||||
|
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
|
||||||
|
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
|
||||||
|
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||||
|
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
|
||||||
|
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||||
|
.highlight .sx { color: #008000 } /* Literal.String.Other */
|
||||||
|
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||||
|
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
|
||||||
|
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
|
||||||
|
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
|
||||||
|
.highlight .vc { color: #19177C } /* Name.Variable.Class */
|
||||||
|
.highlight .vg { color: #19177C } /* Name.Variable.Global */
|
||||||
|
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
|
||||||
|
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
|
|
@ -0,0 +1,61 @@
|
||||||
|
.hll { background-color: #ffffcc }
|
||||||
|
.c { color: #999988; font-style: italic } /* Comment */
|
||||||
|
.err { color: #a61717; background-color: #e3d2d2 } /* Error */
|
||||||
|
.k { color: #000000; font-weight: bold } /* Keyword */
|
||||||
|
.o { color: #000000; font-weight: bold } /* Operator */
|
||||||
|
.cm { color: #999988; font-style: italic } /* Comment.Multiline */
|
||||||
|
.cp { color: #999999; font-weight: bold; font-style: italic } /* Comment.Preproc */
|
||||||
|
.c1 { color: #999988; font-style: italic } /* Comment.Single */
|
||||||
|
.cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
|
||||||
|
.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
|
||||||
|
.ge { color: #000000; font-style: italic } /* Generic.Emph */
|
||||||
|
.gr { color: #aa0000 } /* Generic.Error */
|
||||||
|
.gh { color: #999999 } /* Generic.Heading */
|
||||||
|
.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
|
||||||
|
.go { color: #888888 } /* Generic.Output */
|
||||||
|
.gp { color: #555555 } /* Generic.Prompt */
|
||||||
|
.gs { font-weight: bold } /* Generic.Strong */
|
||||||
|
.gu { color: #aaaaaa } /* Generic.Subheading */
|
||||||
|
.gt { color: #aa0000 } /* Generic.Traceback */
|
||||||
|
.kc { color: #000000; font-weight: bold } /* Keyword.Constant */
|
||||||
|
.kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
|
||||||
|
.kn { color: #000000; font-weight: bold } /* Keyword.Namespace */
|
||||||
|
.kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
|
||||||
|
.kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
|
||||||
|
.kt { color: #445588; font-weight: bold } /* Keyword.Type */
|
||||||
|
.m { color: #009999 } /* Literal.Number */
|
||||||
|
.s { color: #d01040 } /* Literal.String */
|
||||||
|
.na { color: #008080 } /* Name.Attribute */
|
||||||
|
.nb { color: #0086B3 } /* Name.Builtin */
|
||||||
|
.nc { color: #445588; font-weight: bold } /* Name.Class */
|
||||||
|
.no { color: #008080 } /* Name.Constant */
|
||||||
|
.nd { color: #3c5d5d; font-weight: bold } /* Name.Decorator */
|
||||||
|
.ni { color: #800080 } /* Name.Entity */
|
||||||
|
.ne { color: #990000; font-weight: bold } /* Name.Exception */
|
||||||
|
.nf { color: #990000; font-weight: bold } /* Name.Function */
|
||||||
|
.nl { color: #990000; font-weight: bold } /* Name.Label */
|
||||||
|
.nn { color: #555555 } /* Name.Namespace */
|
||||||
|
.nt { color: #000080 } /* Name.Tag */
|
||||||
|
.nv { color: #008080 } /* Name.Variable */
|
||||||
|
.ow { color: #000000; font-weight: bold } /* Operator.Word */
|
||||||
|
.w { color: #bbbbbb } /* Text.Whitespace */
|
||||||
|
.mf { color: #009999 } /* Literal.Number.Float */
|
||||||
|
.mh { color: #009999 } /* Literal.Number.Hex */
|
||||||
|
.mi { color: #009999 } /* Literal.Number.Integer */
|
||||||
|
.mo { color: #009999 } /* Literal.Number.Oct */
|
||||||
|
.sb { color: #d01040 } /* Literal.String.Backtick */
|
||||||
|
.sc { color: #d01040 } /* Literal.String.Char */
|
||||||
|
.sd { color: #d01040 } /* Literal.String.Doc */
|
||||||
|
.s2 { color: #d01040 } /* Literal.String.Double */
|
||||||
|
.se { color: #d01040 } /* Literal.String.Escape */
|
||||||
|
.sh { color: #d01040 } /* Literal.String.Heredoc */
|
||||||
|
.si { color: #d01040 } /* Literal.String.Interpol */
|
||||||
|
.sx { color: #d01040 } /* Literal.String.Other */
|
||||||
|
.sr { color: #009926 } /* Literal.String.Regex */
|
||||||
|
.s1 { color: #d01040 } /* Literal.String.Single */
|
||||||
|
.ss { color: #990073 } /* Literal.String.Symbol */
|
||||||
|
.bp { color: #999999 } /* Name.Builtin.Pseudo */
|
||||||
|
.vc { color: #008080 } /* Name.Variable.Class */
|
||||||
|
.vg { color: #008080 } /* Name.Variable.Global */
|
||||||
|
.vi { color: #008080 } /* Name.Variable.Instance */
|
||||||
|
.il { color: #009999 } /* Literal.Number.Integer.Long */
|
Loading…
Reference in New Issue