From a8cad48fedf78daadf47352118edae4b65c5322c Mon Sep 17 00:00:00 2001 From: Marc Aymerich Date: Sat, 30 May 2015 14:44:05 +0000 Subject: [PATCH] Fixes on payments --- TODO.md | 11 + orchestra/contrib/accounts/models.py | 6 +- orchestra/contrib/bills/actions.py | 16 +- .../bills/locale/ca/LC_MESSAGES/django.mo | Bin 1922 -> 6962 bytes .../bills/locale/ca/LC_MESSAGES/django.po | 176 ++++++------ .../bills/locale/es/LC_MESSAGES/django.mo | Bin 0 -> 3100 bytes .../bills/locale/es/LC_MESSAGES/django.po | 67 +++-- orchestra/contrib/bills/models.py | 55 ++-- .../bills/templates/bills/microspective.css | 4 +- .../bills/templates/bills/microspective.html | 2 +- orchestra/contrib/mailer/backends.py | 5 +- orchestra/contrib/mailer/engine.py | 2 + orchestra/contrib/mailer/models.py | 2 +- orchestra/contrib/mailer/settings.py | 4 +- orchestra/contrib/payments/actions.py | 63 +++-- orchestra/contrib/payments/admin.py | 6 +- .../payments/locale/ca/LC_MESSAGES/django.mo | Bin 0 -> 650 bytes .../payments/locale/ca/LC_MESSAGES/django.po | 250 ++++++++++++++++++ .../payments/locale/es/LC_MESSAGES/django.mo | Bin 0 -> 645 bytes .../payments/locale/es/LC_MESSAGES/django.po | 250 ++++++++++++++++++ .../payments/methods/sepadirectdebit.py | 9 +- orchestra/contrib/payments/models.py | 4 +- .../payments/transaction/get_processes.html | 2 +- orchestra/contrib/systemusers/actions.py | 1 - orchestra/contrib/systemusers/admin.py | 4 +- orchestra/contrib/systemusers/models.py | 4 +- orchestra/utils/html.py | 3 +- orchestra/utils/mail.py | 4 +- requirements.txt | 2 +- 29 files changed, 751 insertions(+), 201 deletions(-) create mode 100644 orchestra/contrib/bills/locale/es/LC_MESSAGES/django.mo create mode 100644 orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.mo create mode 100644 orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.po create mode 100644 orchestra/contrib/payments/locale/es/LC_MESSAGES/django.mo create mode 100644 orchestra/contrib/payments/locale/es/LC_MESSAGES/django.po diff --git a/TODO.md b/TODO.md index 4309f35e..79391137 100644 --- a/TODO.md +++ b/TODO.md @@ -413,3 +413,14 @@ touch /tmp/somefile # inherit registers from parent? # Disable pagination on membership fees (allways one page) + +# datetime metric storage granularity: otherwise innacurate detection of billed metric on order.billed_on + +# Serializers.validation migration to DRF3: grep -r 'attrs, source' *|grep -v '~' +serailzer self.instance on create. + +# generate Direct debit q19 on a protected path, or store it on the transaction.proc +# regenerate direct debit q19 +# add transproc.method for regeneration + +# TODO wrapp admin delete: delete proc undo processing on related transactions diff --git a/orchestra/contrib/accounts/models.py b/orchestra/contrib/accounts/models.py index 13a62e3a..f19a2cf9 100644 --- a/orchestra/contrib/accounts/models.py +++ b/orchestra/contrib/accounts/models.py @@ -14,9 +14,9 @@ from . import settings class Account(auth.AbstractBaseUser): - # Username max_length determined by LINUX system user lentgh: 32 + # Username max_length determined by LINUX system user/group lentgh: 32 username = models.CharField(_("username"), max_length=32, unique=True, - help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."), + help_text=_("Required. 32 characters or fewer. Letters, digits and ./-/_ only."), validators=[ validators.RegexValidator(r'^[\w.-]+$', _("Enter a valid username."), 'invalid') ]) @@ -102,7 +102,7 @@ class Account(auth.AbstractBaseUser): extra_context.update(context) with translation.override(self.language): send_email_template( - template, extra_context, ('marcay@pangea.org',), email_from=email_from, html=html, + template, extra_context, email_to, email_from=email_from, html=html, attachments=attachments) def get_full_name(self): diff --git a/orchestra/contrib/bills/actions.py b/orchestra/contrib/bills/actions.py index 62c5de22..592d3b53 100644 --- a/orchestra/contrib/bills/actions.py +++ b/orchestra/contrib/bills/actions.py @@ -76,8 +76,8 @@ def close_bills(modeladmin, request, queryset): if num == 1: url = change_url(transactions[0]) else: - url = reverse('admin:transactions_transaction_changelist') - url += 'id__in=%s' % ','.join(map(str, transactions)) + url = reverse('admin:payments_transaction_changelist') + url += 'id__in=%s' % ','.join([str(t.id) for t in transactions]) context = { 'url': url, 'num': num, @@ -109,19 +109,15 @@ close_bills.url_name = 'close' def send_bills(modeladmin, request, queryset): - num = 0 for bill in queryset: if not validate_contact(request, bill): return - num += 1 - if num == 1: - bill.send() - else: - # Batch email - queryset.send() + num = 0 for bill in queryset: + bill.send() modeladmin.log_change(request, bill, 'Sent') - messages.success(request, ungetetx( + num += 1 + messages.success(request, ungettext( _("One bill has been sent."), _("%i bills have been sent.") % num, num)) diff --git a/orchestra/contrib/bills/locale/ca/LC_MESSAGES/django.mo b/orchestra/contrib/bills/locale/ca/LC_MESSAGES/django.mo index e2aeb0f728d5939c292dea231a89cb8a472c16be..0e97045d1b0dc71795f321951cfb87dfbce934a4 100644 GIT binary patch literal 6962 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 K3nuo5%KrlaG11)s literal 1922 zcmZ{j%WoV-5QmFkUYiggBoGLXMo}bN$=GX)h-hs`8N9P*#lEsT>&P5Hy|e9g$FtMp zo*pL_k>J3;z=cBuMdB8y9X6apAxP2?-$~<-o5t<7^~MYihpkp6aUVnyR}e zWM0n^kyq*ScgU^9qflq?p7W^JOiuI4h z`ezUi{f5^Q;O`(z(x1ipuY&i$r?5XWL-ZJU9K;r#1WVv)5D%R#_Gdx%djVvB7eTh~ z7yES(4|Vb4^VdMOHvrlG7Kn#pymoNsUGNjEf5FGotoQhR{SQIT(MRAZ@HWWyz5zMj z??CqdL$Uu8$ocsd00sqeUSZKFPMSs=N8Dn_zZ*x+c*w+6~b{p3*o`BK$TvGuw5QpC!CuT z5VmzNp2383bF$drcsW+iFURmAglp(vynxBEg9XTS#5sN*!grgDk~m~+np{LO5vkl4 zCb#0;tlLl3TqXwlVjz3Mrp|k%Fg3iqjbR2)c;or*BR9Rf2>W6_K zKaR;Ct7HgqVoRxqRyx@;I#RUOZZ?Bf*rRGcm>i?3$|9>%r%ggtb0dk398wL3>&20l zp^m@Fr>G-K3k zmx3kUjie6XkX*OQy zZ3ceVYqq_rFWzZan)UPVwOc`{Av5QNTq?12##ThF-)M-I-web`(Ddt#D}J@w4SK!H zP)$a;94RkUa$FG&zqQ`ykXIUwE3uw8b~M#NsLgsanBH%3zFb-}i9_J=621xaLvIvG{OrGa*(PMljAdo^RnSw$r2WSOllEsOip z)!9V6u__klmP=IX7?+_*M$!ton=6#}w3Jb6586Z}k(OM%GLlxyd2X6|62)jU6(iVO zBxWo$FHqFV8Zn$U#k>fxZ8C=*LW!j4AXs8U;?9>Dp_+Yo{ZE-wXdHD>3VKUNGSYXx zW}~~gL6DeaCel=sk;8R`Jy3IcPjc0xeEn{{M;k$F4XH*k7lqGuCUa@68cDi(m_3>_ z!8-o)qzgu9b+kdJ8?5(RVQ|m}^$nj|^&09Qd83}@`iCCw^`HYL-X\n" "Language-Team: LANGUAGE \n" @@ -28,61 +28,63 @@ msgstr "Vista" #: actions.py:55 msgid "Selected bills should be in open state" -msgstr "" +msgstr "Les factures seleccionades han d'estar en estat obert" #: actions.py:73 msgid "Selected bills have been closed" -msgstr "" +msgstr "Les factures seleccionades han estat tancades" #: actions.py:86 #, python-format msgid "One related transaction has been created" -msgstr "" +msgstr "S'ha creat una transacció" #: actions.py:87 #, python-format msgid "%(num)i related transactions have been created" -msgstr "" +msgstr "S'han creat les %(num)i següents transaccions" #: actions.py:93 msgid "Are you sure about closing the following bills?" -msgstr "" +msgstr "Estàs a punt de tancar les següents factures, estàs segur?" #: actions.py:94 msgid "" "Once a bill is closed it can not be further modified.

Please select a " "payment source for the selected bills" msgstr "" +"Una vegada la factura estigui tancada no podrà ser modificada.

Si us " +"plau selecciona un mètode de pagament per les factures seleccionades" #: actions.py:107 msgid "Close" -msgstr "" +msgstr "Tanca" #: actions.py:125 msgid "One bill has been sent." -msgstr "" +msgstr "S'ha creat una factura" #: actions.py:126 #, python-format msgid "%i bills have been sent." -msgstr "" +msgstr "S'han enviat %i factures." #: actions.py:128 msgid "Resend" -msgstr "" +msgstr "Reenviat" #: actions.py:189 #, python-format msgid "%(norders)s orders and %(nlines)s lines undoed." -msgstr "" +msgstr "%(norders)s ordres i %(nlines)s línies desfetes." #: actions.py:208 msgid "Lines moved" -msgstr "" +msgstr "Línies mogudes" #: admin.py:49 admin.py:93 admin.py:128 forms.py:11 msgid "Total" -msgstr "" +msgstr "Total" #: admin.py:80 msgid "Description" @@ -90,52 +92,52 @@ msgstr "Descripció" #: admin.py:88 msgid "Subtotal" -msgstr "" +msgstr "Subtotal" #: admin.py:118 msgid "Is open" -msgstr "" +msgstr "És oberta" #: admin.py:123 msgid "Subline" -msgstr "" +msgstr "Sublínia" #: admin.py:157 msgid "No bills selected." -msgstr "" +msgstr "No hi ha factures seleccionades" #: admin.py:164 #, python-format msgid "Manage %s bill lines." -msgstr "" +msgstr "Gestiona %s línies de factura." #: admin.py:166 msgid "Bill not in open state." -msgstr "" +msgstr "La factura no està en estat obert" #: admin.py:169 msgid "Not all bills are in open state." -msgstr "" +msgstr "No totes les factures estan en estat obert" #: admin.py:170 msgid "Manage bill lines of multiple bills." -msgstr "" +msgstr "Gestiona línies de factura de multiples factures." #: admin.py:190 msgid "Raw" -msgstr "" +msgstr "Raw" #: admin.py:208 msgid "Created" -msgstr "" +msgstr "Creada" #: admin.py:213 msgid "lines" -msgstr "" +msgstr "línies" #: admin.py:218 templates/bills/microspective.html:118 msgid "total" -msgstr "" +msgstr "total" #: admin.py:226 models.py:88 models.py:352 msgid "type" @@ -167,11 +169,11 @@ msgstr "Rectificació de quota de soci" #: filters.py:22 msgid "Pro-forma" -msgstr "" +msgstr "Pro-forma" #: filters.py:41 msgid "positive price" -msgstr "" +msgstr "preu positiu" #: filters.py:46 filters.py:64 msgid "Yes" @@ -183,69 +185,71 @@ msgstr "No" #: filters.py:59 msgid "has bill contact" -msgstr "" +msgstr "té contacte de facturació" #: forms.py:9 msgid "Number" -msgstr "" +msgstr "Número" #: forms.py:10 msgid "Account" -msgstr "" +msgstr "Compte" #: forms.py:12 msgid "Type" -msgstr "" +msgstr "Tipus" #: forms.py:13 msgid "Source" -msgstr "" +msgstr "Font" #: helpers.py:10 msgid "" "{relation} account \"{account}\" does not have a declared invoice contact. " "You should provide one" msgstr "" +"{relation} compte \"{account}\" no te un contacte de facturació. Hauries de " +"proporcionar un" #: helpers.py:17 msgid "Related" -msgstr "" +msgstr "Relacionat" #: helpers.py:24 msgid "Main" -msgstr "" +msgstr "Principal" #: models.py:23 models.py:86 msgid "account" -msgstr "" +msgstr "compte" #: models.py:25 msgid "name" -msgstr "" +msgstr "nom" #: models.py:26 msgid "Account full name will be used when left blank." -msgstr "" +msgstr "S'emprarà el nom complet del compte quan es deixi en blanc." #: models.py:27 msgid "address" -msgstr "" +msgstr "adreça" #: models.py:28 msgid "city" -msgstr "" +msgstr "ciutat" #: models.py:30 msgid "zip code" -msgstr "" +msgstr "codi postal" #: models.py:31 msgid "Enter a valid zipcode." -msgstr "" +msgstr "Introdueix un codi postal vàlid." #: models.py:32 msgid "country" -msgstr "" +msgstr "país" #: models.py:35 msgid "VAT number" @@ -253,51 +257,51 @@ msgstr "NIF" #: models.py:67 msgid "Paid" -msgstr "" +msgstr "Pagat" #: models.py:68 msgid "Pending" -msgstr "" +msgstr "Pendent" #: models.py:69 msgid "Bad debt" -msgstr "" +msgstr "Incobrable" #: models.py:81 msgid "Amendment Fee" -msgstr "" +msgstr "Rectificació de quota de soci" #: models.py:82 msgid "Pro forma" -msgstr "" +msgstr "Pro forma" #: models.py:85 msgid "number" -msgstr "" +msgstr "número" #: models.py:89 msgid "created on" -msgstr "" +msgstr "creat el" #: models.py:90 msgid "closed on" -msgstr "" +msgstr "tancat el" #: models.py:91 msgid "open" -msgstr "" +msgstr "obert" #: models.py:92 msgid "sent" -msgstr "" +msgstr "enviat" #: models.py:93 msgid "due on" -msgstr "" +msgstr "es deu" #: models.py:94 msgid "updated on" -msgstr "" +msgstr "actualitzada el" #: models.py:97 msgid "comments" @@ -305,11 +309,11 @@ msgstr "comentaris" #: models.py:98 msgid "HTML" -msgstr "" +msgstr "HTML" #: models.py:285 msgid "bill" -msgstr "" +msgstr "factura" #: models.py:286 models.py:350 templates/bills/microspective.html:73 msgid "description" @@ -332,7 +336,7 @@ msgstr "quantitat" #: models.py:290 templates/bills/microspective.html:77 #: templates/bills/microspective.html:111 msgid "subtotal" -msgstr "" +msgstr "subtotal" #: models.py:291 msgid "tax" @@ -340,67 +344,69 @@ msgstr "impostos" #: models.py:292 msgid "start" -msgstr "" +msgstr "iniciar" #: models.py:293 msgid "end" -msgstr "" +msgstr "finalitzar" #: models.py:295 msgid "Informative link back to the order" -msgstr "" +msgstr "Enllaç informatiu de l'ordre" #: models.py:296 msgid "order billed" -msgstr "" +msgstr "ordre facturada" #: models.py:297 msgid "order billed until" -msgstr "" +msgstr "ordre facturada fins a" #: models.py:298 msgid "created" -msgstr "" +msgstr "creada" #: models.py:300 msgid "amended line" -msgstr "" +msgstr "línia rectificada" #: models.py:343 msgid "Volume" -msgstr "" +msgstr "Volum" #: models.py:344 msgid "Compensation" -msgstr "" +msgstr "Compensació" #: models.py:345 msgid "Other" -msgstr "" +msgstr "Altre" #: models.py:349 msgid "bill line" -msgstr "" +msgstr "línia de factura" #: templates/bills/microspective-fee.html:107 msgid "Due date" -msgstr "" +msgstr "Data de pagament" #: templates/bills/microspective-fee.html:108 #, python-format msgid "On %(bank_account)s" -msgstr "" +msgstr "Al %(bank_account)s" #: templates/bills/microspective-fee.html:114 #, python-format msgid "From %(ini)s to %(end)s" -msgstr "" +msgstr "De %(ini)s a %(end)s" #: templates/bills/microspective-fee.html:121 msgid "" "\n" "With your membership you are supporting ...\n" msgstr "" +"\n" +"Amb la teva quota de soci estàs donant suport ...\n" #: templates/bills/microspective.html:49 msgid "DUE DATE" @@ -411,18 +417,17 @@ msgid "TOTAL" msgstr "TOTAL" #: templates/bills/microspective.html:57 -#, fuzzy, python-format -#| msgid "%(bill_type|upper)s DATE " +#, python-format msgid "%(bill_type)s DATE" -msgstr "DATA %(bill_type|upper)s" +msgstr "DATA %(bill_type)s" #: templates/bills/microspective.html:74 msgid "period" -msgstr "" +msgstr "període" #: templates/bills/microspective.html:75 msgid "hrs/qty" -msgstr "hrs/quant" +msgstr "hrs/qnt" #: templates/bills/microspective.html:76 msgid "rate/price" @@ -446,15 +451,6 @@ msgid "PAYMENT" msgstr "PAGAMENT" #: templates/bills/microspective.html:140 -#, fuzzy, python-format -#| msgid "" -#| "\n" -#| " You can pay our %(type)s by bank transfer. " -#| "
\n" -#| " Please make sure to state your name and the " -#| "%(type)s number.\n" -#| " Our bank account number is
\n" -#| " " msgid "" "\n" " You can pay our %(type)s by bank transfer.
\n" @@ -464,8 +460,8 @@ msgid "" " " msgstr "" "\n" -"Pots pagar aquesta %(type)s per transferencia banacaria.
Inclou el " -"teu nom i el numero de %(type)s. El nostre compte bancari és" +"Pots pagar aquesta %(type)s per transferència bancaria.
Inclou el " +"teu nom i el número de %(type)s. El nostre compte bancari és" #: templates/bills/microspective.html:149 msgid "QUESTIONS" @@ -481,3 +477,9 @@ msgid "" " your message.\n" " " msgstr "" +"\n" +" Si tens algun dubte o pregunta sobre la teva %(type)s, si " +"us plau\n" +" contacta amb nosaltres a %(email)s. Et respondrem el més " +"ràpidament possible.\n" +" " diff --git a/orchestra/contrib/bills/locale/es/LC_MESSAGES/django.mo b/orchestra/contrib/bills/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..258c2c4c2ca0b50aee0744613f6d614dba7082f8 GIT binary patch literal 3100 zcmaJ@&2Jk;6dy{M8Dd3I;sd%ySI{G4C* z@4X-}9>#nC^T0Jii~w)mgAa^Lz~6zN1HT7;c&!lofiLV8q6$oa)4;EQw*dbJ-T~aR zPlz$#0pJb5DiD97QLL8=e7-;hglS=b_W&L6df?l@JAv;5&jCLz-XFYf@P53&V?gF` z0{AHKB_Otnw}5Q-9Uwvz?*ZBF2SEIZkML0fegfqEmw;!HgRg<_Vtoj~e+&Eq$Z^;k zg?Iw^Ch#%fcR+srC-5%dJ{X$;-VeM9cm@bl;%u>YK+eZ&K+e}&z*~VAfcFDG26B8q z0NL(Oz}JC41MdaC2&2s7e1We5k6`@&3Z8Hj`p+xq{W{xKH^w4nHPt=H?9MjX(?o(Tu zvy?h%d`G#_$+nx`)zU(&q*v6FXBGL(DM~H*RHlmhY}m-2B55K@SJe(LChN6fdsn+n z9L__KVQ4dx(qJ=bPgjjaY_nAFa0s+2*EoVcoy(L@wKXK$HcJQLUBUYZB{`jKb~;MM z)Nv}Ow(c~jWu9b8L&K^kbv)un=~+eVI*!SyB<_>+Qray(9m$^;Oh_yg;b1a_==HcWR`0rL#Bq}$>{;(wo-;d zr+CXQMw&+LW}rClY1{EiPnifaCFDYEt+ZLQI>Zx{ol~9He~{fUwqBcVUiOZSW4q2P zX6K(2GtEY$Hs4wjGuWj>b-6a+TD9vYwlWgcOi_f$#Vq{II@?38wb3J(I8Vg&70oX6#S@@IW(oCo{e-zt7vp`ESa86ri+gD zDpp|%Be)|ucaMIC)sA&JtHFC%%}K$d8n|0U)${CmBy3bHR8BKju`sYAmU6S3$NpQZ zJjN^E`&FC8@S#W>vI%OMUoO#VwkmUCrP2~BTCIy!=f}>aeUT`qZ6q9WHWs z=bH1i(wy{Z(Bh^=|5{h3+2y%8ny)l!G+Ap@>T@S5)#_qxX=xf;O*g|e30g|_$~0G* zKe@~yPtMJqi1ny--K{+cwNY=>w)jnqj+bVvNl}KN1!*f&s?MilNi4NFPT{I_UZqpZ zt=Zt%*1kgTf|?1@7N%RKV{M(57UImwIGDAr=gVZ0eCel-9*1D?o2g+#k4(|T$nlaW zEo3TE9(~i5j-WYmhwvfMm!(yiP@_|&38m9A7uvc(!}g&!85!Ga^X(#NklFaAr<|o| zhmwxcJd2x?6lS2iWe)DQi{g@|R4aqNmwf48$$6bajC&gfT=zs$3ZdCv#QAL1w@6@a01rUm8|J@l0mH&f)ez zB|=<-H7RDn7-iq~REe5TnG_TQnas-+D(BDxF(kq3?#8#se2Ua}2FLNc@#FW!A&>Ms zn@c0qqOw?TLLKwdVx=}eQ*YGqxGAd2qfNSqK%s%T6VPS0h!HDq!IpR7`=(?DWxcV0XSflD;UAGHY5E6)HADM^82(q96\n" "Language-Team: LANGUAGE \n" @@ -20,47 +20,49 @@ msgstr "" #: actions.py:37 msgid "Download" -msgstr "" +msgstr "Descarga" #: actions.py:47 msgid "View" -msgstr "" +msgstr "Vista" #: actions.py:55 msgid "Selected bills should be in open state" -msgstr "" +msgstr "Las facturas seleccionadas están en estado abierto" #: actions.py:73 msgid "Selected bills have been closed" -msgstr "" +msgstr "Las facturas seleccionadas han sido cerradas" #: actions.py:86 #, python-format msgid "One related transaction has been created" -msgstr "" +msgstr "Se ha creado una transacción" #: actions.py:87 #, python-format msgid "%(num)i related transactions have been created" -msgstr "" +msgstr "Se han creado %(num)i transacciones" #: actions.py:93 msgid "Are you sure about closing the following bills?" -msgstr "" +msgstr "Estás a punto de cerrar las sigüientes facturas. ¿Estás seguro?" #: actions.py:94 msgid "" "Once a bill is closed it can not be further modified.

Please select a " "payment source for the selected bills" msgstr "" +"Una vez cerrada la factura ya no se podrá modificar.

Por favor " +"seleciona un metodo de pago para las facturas seleccionadas" #: actions.py:107 msgid "Close" -msgstr "" +msgstr "Cerrar" #: actions.py:125 msgid "One bill has been sent." -msgstr "" +msgstr "Se ha enviado una factura" #: actions.py:126 #, python-format @@ -143,7 +145,7 @@ msgstr "" #: admin.py:243 msgid "Payment" -msgstr "" +msgstr "Pago" #: filters.py:17 msgid "All" @@ -151,19 +153,19 @@ msgstr "" #: filters.py:18 models.py:78 msgid "Invoice" -msgstr "" +msgstr "Factura" #: filters.py:19 models.py:79 msgid "Amendment invoice" -msgstr "" +msgstr "Factura rectificative" #: filters.py:20 models.py:80 msgid "Fee" -msgstr "" +msgstr "Quota de socio" #: filters.py:21 msgid "Amendment fee" -msgstr "" +msgstr "Quota rectificativa" #: filters.py:22 msgid "Pro-forma" @@ -382,17 +384,17 @@ msgstr "" #: templates/bills/microspective-fee.html:107 msgid "Due date" -msgstr "" +msgstr "Fecha de pago" #: templates/bills/microspective-fee.html:108 #, python-format msgid "On %(bank_account)s" -msgstr "" +msgstr "En %(bank_account)s" #: templates/bills/microspective-fee.html:114 #, python-format msgid "From %(ini)s to %(end)s" -msgstr "" +msgstr "Desde %(ini)s hasta %(end)s" #: templates/bills/microspective-fee.html:121 msgid "" @@ -402,45 +404,45 @@ msgstr "" #: templates/bills/microspective.html:49 msgid "DUE DATE" -msgstr "" +msgstr "VENCIMIENTO" #: templates/bills/microspective.html:53 msgid "TOTAL" -msgstr "" +msgstr "TOTAL" #: templates/bills/microspective.html:57 #, python-format msgid "%(bill_type)s DATE" -msgstr "" +msgstr "FECHA %(bill_type)s" #: templates/bills/microspective.html:74 msgid "period" -msgstr "" +msgstr "periodo" #: templates/bills/microspective.html:75 msgid "hrs/qty" -msgstr "" +msgstr "hrs/cant" #: templates/bills/microspective.html:76 msgid "rate/price" -msgstr "" +msgstr "tarifa/precio" #: templates/bills/microspective.html:111 #: templates/bills/microspective.html:114 msgid "VAT" -msgstr "" +msgstr "IVA" #: templates/bills/microspective.html:114 msgid "taxes" -msgstr "" +msgstr "impuestos" #: templates/bills/microspective.html:130 msgid "COMMENTS" -msgstr "" +msgstr "COMENTARIOS" #: templates/bills/microspective.html:136 msgid "PAYMENT" -msgstr "" +msgstr "PAGO" #: templates/bills/microspective.html:140 #, python-format @@ -452,6 +454,9 @@ msgid "" " Our bank account number is
\n" " " msgstr "" +"\n" +"Puedes pagar esta %(type)s por transferencia bancaria.
Incloye tu " +"nombre y el número de %(type)s. Nuestra cuenta bancaria es" #: templates/bills/microspective.html:149 msgid "QUESTIONS" @@ -467,3 +472,9 @@ msgid "" " your message.\n" " " msgstr "" +"\n" +" Si tienes alguna duda o pregunta sobre tu %(type)s, por " +"favor\n" +" contacta con nosotros en %(email)s. Te responderemos lo más " +"rapidamente posible.\n" +" " diff --git a/orchestra/contrib/bills/models.py b/orchestra/contrib/bills/models.py index 8ad88c96..64707f94 100644 --- a/orchestra/contrib/bills/models.py +++ b/orchestra/contrib/bills/models.py @@ -142,7 +142,7 @@ class Bill(models.Model): def get_type(self): return self.type or self.get_class_type() - def set_number(self): + def get_number(self): cls = type(self) bill_type = self.get_type() if bill_type == self.BILL: @@ -162,7 +162,7 @@ class Bill(models.Model): number_length = settings.BILLS_NUMBER_LENGTH zeros = (number_length - len(str(number))) * '0' number = zeros + str(number) - self.number = '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number) + return '{prefix}{year}{number}'.format(prefix=prefix, year=year, number=number) def get_due_date(self, payment=None): now = timezone.now() @@ -178,13 +178,14 @@ class Bill(models.Model): if not self.due_on: self.due_on = self.get_due_date(payment=payment) self.total = self.get_total() - self.html = self.render(payment=payment) transaction = None if self.get_type() != self.PROFORMA: transaction = self.transactions.create(bill=self, source=payment, amount=self.total) self.closed_on = timezone.now() self.is_open = False self.is_sent = False + self.number = self.get_number() + self.html = self.render(payment=payment) self.save() return transaction @@ -207,37 +208,37 @@ class Bill(models.Model): self.save(update_fields=['is_sent']) def render(self, payment=False, language=None): - if payment is False: - payment = self.account.paymentsources.get_default() - context = Context({ - 'bill': self, - 'lines': self.lines.all().prefetch_related('sublines'), - 'seller': self.seller, - 'buyer': self.buyer, - 'seller_info': { - 'phone': settings.BILLS_SELLER_PHONE, - 'website': settings.BILLS_SELLER_WEBSITE, - 'email': settings.BILLS_SELLER_EMAIL, - 'bank_account': settings.BILLS_SELLER_BANK_ACCOUNT, - }, - 'currency': settings.BILLS_CURRENCY, - 'payment': payment and payment.get_bill_context(), - 'default_due_date': self.get_due_date(payment=payment), - 'now': timezone.now(), - }) - template_name = 'BILLS_%s_TEMPLATE' % self.get_type() - template = getattr(settings, template_name, settings.BILLS_DEFAULT_TEMPLATE) - bill_template = loader.get_template(template) with translation.override(language or self.account.language): + if payment is False: + payment = self.account.paymentsources.get_default() + context = Context({ + 'bill': self, + 'lines': self.lines.all().prefetch_related('sublines'), + 'seller': self.seller, + 'buyer': self.buyer, + 'seller_info': { + 'phone': settings.BILLS_SELLER_PHONE, + 'website': settings.BILLS_SELLER_WEBSITE, + 'email': settings.BILLS_SELLER_EMAIL, + 'bank_account': settings.BILLS_SELLER_BANK_ACCOUNT, + }, + 'currency': settings.BILLS_CURRENCY, + 'payment': payment and payment.get_bill_context(), + 'default_due_date': self.get_due_date(payment=payment), + 'now': timezone.now(), + }) + template_name = 'BILLS_%s_TEMPLATE' % self.get_type() + template = getattr(settings, template_name, settings.BILLS_DEFAULT_TEMPLATE) + bill_template = loader.get_template(template) html = bill_template.render(context) - html = html.replace('-pageskip-', '') + html = html.replace('-pageskip-', '') return html def save(self, *args, **kwargs): if not self.type: self.type = self.get_type() - if not self.number or (self.number.startswith('O') and not self.is_open): - self.set_number() + if not self.number: + self.number = self.get_number() super(Bill, self).save(*args, **kwargs) def get_subtotals(self): diff --git a/orchestra/contrib/bills/templates/bills/microspective.css b/orchestra/contrib/bills/templates/bills/microspective.css index d2e8f4dd..7e6730cf 100644 --- a/orchestra/contrib/bills/templates/bills/microspective.css +++ b/orchestra/contrib/bills/templates/bills/microspective.css @@ -175,12 +175,12 @@ a:hover { } #lines .column-description { - width: 40%; + width: 39%; text-align: left; } #lines .column-period { - width: 22%; + width: 23%; } #lines .column-quantity { diff --git a/orchestra/contrib/bills/templates/bills/microspective.html b/orchestra/contrib/bills/templates/bills/microspective.html index 1b2e7162..e20e2b0b 100644 --- a/orchestra/contrib/bills/templates/bills/microspective.html +++ b/orchestra/contrib/bills/templates/bills/microspective.html @@ -135,7 +135,7 @@

{% trans "PAYMENT" %} {% if payment.message %} - {{ payment.message | safe }} + {{ payment.message|safe }} {% else %} {% blocktrans with type=bill.get_type_display.lower %} You can pay our {{ type }} by bank transfer.
diff --git a/orchestra/contrib/mailer/backends.py b/orchestra/contrib/mailer/backends.py index f078e7ef..a520ee4a 100644 --- a/orchestra/contrib/mailer/backends.py +++ b/orchestra/contrib/mailer/backends.py @@ -12,11 +12,10 @@ class EmailBackend(BaseEmailBackend): """ A wrapper that manages a queued SMTP system. """ - messages = 0 - def send_messages(self, email_messages): if not email_messages: return + # Count messages per request cache = get_request_cache() key = 'mailer.sent_messages' sent_messages = cache.get(key) or 0 @@ -24,7 +23,7 @@ class EmailBackend(BaseEmailBackend): cache.set(key, sent_messages) is_bulk = len(email_messages) > 1 - if sent_messages > settings.MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD: + if sent_messages > settings.MAILER_NON_QUEUED_PER_REQUEST_THRESHOLD: is_bulk = True default_priority = Message.NORMAL if is_bulk else Message.CRITICAL num_sent = 0 diff --git a/orchestra/contrib/mailer/engine.py b/orchestra/contrib/mailer/engine.py index da6f4dbc..b70e6e9f 100644 --- a/orchestra/contrib/mailer/engine.py +++ b/orchestra/contrib/mailer/engine.py @@ -14,6 +14,8 @@ from .models import Message def send_message(message, num=0, connection=None, bulk=100): + if not message.pk: + message.save() if num >= bulk: connection.close() connection = None diff --git a/orchestra/contrib/mailer/models.py b/orchestra/contrib/mailer/models.py index be952cb8..fb7217f6 100644 --- a/orchestra/contrib/mailer/models.py +++ b/orchestra/contrib/mailer/models.py @@ -50,7 +50,7 @@ class Message(models.Model): def sent(self): self.state = self.SENT - self.save() + self.save(update_fiields=('state',)) def log(self, error): result = SMTPLog.SUCCESS diff --git a/orchestra/contrib/mailer/settings.py b/orchestra/contrib/mailer/settings.py index 9e0d42e5..2711cbb5 100644 --- a/orchestra/contrib/mailer/settings.py +++ b/orchestra/contrib/mailer/settings.py @@ -13,7 +13,7 @@ MAILER_MESSAGES_CLEANUP_DAYS = Setting('MAILER_MESSAGES_CLEANUP_DAYS', ) -MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD = Setting('MAILER_NON_QUEUED_MAILS_PER_REQUEST_THRESHOLD', +MAILER_NON_QUEUED_PER_REQUEST_THRESHOLD = Setting('MAILER_NON_QUEUED_PER_REQUEST_THRESHOLD', 2, - help_text=_("Number of emails that will be sent directly before starting to queue them."), + help_text=_("Number of emails that will be sent immediately before starting to queue them."), ) diff --git a/orchestra/contrib/payments/actions.py b/orchestra/contrib/payments/actions.py index d4dce049..78349c8d 100644 --- a/orchestra/contrib/payments/actions.py +++ b/orchestra/contrib/payments/actions.py @@ -1,6 +1,7 @@ from functools import partial from django.contrib import messages +from django.contrib.admin import actions from django.db import transaction from django.shortcuts import render from django.utils.safestring import mark_safe @@ -18,23 +19,25 @@ from .models import Transaction def process_transactions(modeladmin, request, queryset): processes = [] if queryset.exclude(state=Transaction.WAITTING_PROCESSING).exists(): - msg = _("Selected transactions must be on '{state}' state") - messages.error(request, msg.format(state=Transaction.WAITTING_PROCESSING)) + messages.error(request, + _("Selected transactions must be on '{state}' state").format( + state=Transaction.WAITTING_PROCESSING) + ) return for method, transactions in queryset.group_by('source__method').items(): if method is not None: method = PaymentMethod.get(method) procs = method.process(transactions) processes += procs - for trans in transactions: - modeladmin.log_change(request, trans, _("Processed")) + for transaction in transactions: + modeladmin.log_change(request, transaction, _("Processed")) if not processes: return opts = modeladmin.model._meta num = len(queryset) context = { 'title': ungettext( - _("Selected transaction has been processed."), + _("One selected transaction has been processed."), _("%s Selected transactions have been processed.") % num, num), 'content_message': ungettext( @@ -54,9 +57,9 @@ def process_transactions(modeladmin, request, queryset): @transaction.atomic @action_with_confirmation() def mark_as_executed(modeladmin, request, queryset): - for trans in queryset: - trans.mark_as_executed() - modeladmin.log_change(request, trans, _("Executed")) + for transaction in queryset: + transaction.mark_as_executed() + modeladmin.log_change(request, transaction, _("Executed")) num = len(queryset) msg = ungettext( _("One selected transaction has been marked as executed."), @@ -70,9 +73,9 @@ mark_as_executed.verbose_name = _("Mark as executed") @transaction.atomic @action_with_confirmation() def mark_as_secured(modeladmin, request, queryset): - for trans in queryset: - trans.mark_as_secured() - modeladmin.log_change(request, trans, _("Secured")) + for transaction in queryset: + transaction.mark_as_secured() + modeladmin.log_change(request, transaction, _("Secured")) num = len(queryset) msg = ungettext( _("One selected transaction has been marked as secured."), @@ -86,9 +89,9 @@ mark_as_secured.verbose_name = _("Mark as secured") @transaction.atomic @action_with_confirmation() def mark_as_rejected(modeladmin, request, queryset): - for trans in queryset: - trans.mark_as_rejected() - modeladmin.log_change(request, trans, _("Rejected")) + for transaction in queryset: + transaction.mark_as_rejected() + modeladmin.log_change(request, transaction, _("Rejected")) num = len(queryset) msg = ungettext( _("One selected transaction has been marked as rejected."), @@ -157,9 +160,9 @@ abort.verbose_name = _("Abort") @transaction.atomic @action_with_confirmation(extra_context=_format_commit) def commit(modeladmin, request, queryset): - for trans in queryset: - trans.mark_as_rejected() - modeladmin.log_change(request, trans, _("Rejected")) + for transaction in queryset: + transaction.mark_as_rejected() + modeladmin.log_change(request, transaction, _("Rejected")) num = len(queryset) msg = ungettext( _("One selected transaction has been marked as rejected."), @@ -168,3 +171,29 @@ def commit(modeladmin, request, queryset): modeladmin.message_user(request, msg) commit.url_name = 'commit' commit.verbose_name = _("Commit") + + +def delete_selected(modeladmin, request, queryset): + """ Has to have same name as admin.actions.delete_selected """ + if not queryset: + messages.warning(request, "No transaction process selected.") + return + if queryset.exclude(transactions__state=Transaction.WAITTING_EXECUTION).exists(): + messages.error(request, "Done nothing. Not all related transactions in waitting execution.") + return + # Store before deleting + related_transactions = [] + for process in queryset: + related_transactions.extend(process.transactions.filter(state=Transaction.WAITTING_EXECUTION)) + response = actions.delete_selected(modeladmin, request, queryset) + if response is None: + # Confirmation + num = 0 + for transaction in related_transactions: + transaction.state = Transaction.WAITTING_PROCESSING + transaction.save(update_fields=('state',)) + num += 1 + modeladmin.log_change(request, transaction, _("Unprocessed")) + messages.success(request, "%i related transactions marked as waitting for processing." % num) + return response +delete_selected.short_description = actions.delete_selected.short_description diff --git a/orchestra/contrib/payments/admin.py b/orchestra/contrib/payments/admin.py index 6d0038df..3d52bdf9 100644 --- a/orchestra/contrib/payments/admin.py +++ b/orchestra/contrib/payments/admin.py @@ -122,8 +122,8 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin): fields = ('data', 'file_url', 'created_at') readonly_fields = ('data', 'file_url', 'display_transactions', 'created_at') inlines = [TransactionInline] - actions = (actions.mark_process_as_executed, actions.abort, actions.commit) - change_view_actions = actions + change_view_actions = (actions.mark_process_as_executed, actions.abort, actions.commit) + actions = change_view_actions + (actions.delete_selected,) def file_url(self, process): if process.file: @@ -138,7 +138,7 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin): # Because of values_list this query doesn't benefit from prefetch_related tx_ids = process.transactions.values_list('id', flat=True) for tx_id in tx_ids: - ids.append('#%i' % tx_id) + ids.append(str(tx_id)) counter += 1 if counter > 10: counter = 0 diff --git a/orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.mo b/orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d130159a318dea4c4dfebd933d5a9adc45a416b1 GIT binary patch literal 650 zcmZ{h&2G~`6omtVjhC!hTqKY{Wl|@iC~};rZsHURI|+$X33g-W#+lZh2{U8bJP3Op zgFWxTvv8eOgbhdf=0`er=FHsR&z^j5kscGziMPa4!Y3Ndi4F0IxOvoS{iGR*msCL8 zziR3aO1Hv5Cdv|Sn;}EswN(|jBIjkfhkVO*fore|_Nvy9ad`tg&s8lgP>tO}bP-HJ z)>Veu&-BnYRx4QyUm5@OVcBlYwYtXKvS`h&P#dA72lHU`F}MujDqJk1+0$ zQ;0RYs0+hV<$*JwrEH{;5-G{X+@c3vw{ynaGuG`v=e_sNJ#k57WDEQzn!_J_pTl6m zk{KHZ@L}d9(aD$DG<0HaEK4<)rsP&>4<@TPhG~$5;D<>N#pl6zya<=eAz5Wn^8#6l zyz(FprkATGvLDCirD!W%96b~@iIVX6zE0b9MoLw=(_P7h>>obXpdGBz z3F{qwO{@)S7Rp?$g)BViWx_i1vevw06QwKTf!rOoX3*`!{c`YH!ixcP-t?VT@U=!` uIc#`tsS40Qt}@N_uOI(3x1v~p60oFLH94xC#iqSE*8+Hz-S_ps9sL8ONWZ!O literal 0 HcmV?d00001 diff --git a/orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.po b/orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.po new file mode 100644 index 00000000..3d9c3bba --- /dev/null +++ b/orchestra/contrib/payments/locale/ca/LC_MESSAGES/django.po @@ -0,0 +1,250 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-05-28 16:40+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: actions.py:21 +msgid "Selected transactions must be on '{state}' state" +msgstr "" + +#: actions.py:30 +msgid "Processed" +msgstr "" + +#: actions.py:37 +msgid "Selected transaction has been processed." +msgstr "" + +#: actions.py:38 +#, python-format +msgid "%s Selected transactions have been processed." +msgstr "" + +#: actions.py:41 +msgid "" +"The following transaction process has been generated, you may want to save " +"it on your computer now." +msgstr "" + +#: actions.py:43 +#, python-format +msgid "" +"The following %s transaction processes have been generated, you may want to " +"save it on your computer now." +msgstr "" + +#: actions.py:46 +msgid "Process" +msgstr "" + +#: actions.py:59 actions.py:130 models.py:93 models.py:161 +msgid "Executed" +msgstr "" + +#: actions.py:62 +msgid "One selected transaction has been marked as executed." +msgstr "" + +#: actions.py:63 +#, python-format +msgid "%s selected transactions have been marked as executed." +msgstr "" + +#: actions.py:67 actions.py:138 +msgid "Mark as executed" +msgstr "" + +#: actions.py:75 models.py:94 +msgid "Secured" +msgstr "" + +#: actions.py:78 +msgid "One selected transaction has been marked as secured." +msgstr "" + +#: actions.py:79 +#, python-format +msgid "%s selected transactions have been marked as secured." +msgstr "" + +#: actions.py:83 +msgid "Mark as secured" +msgstr "" + +#: actions.py:91 actions.py:162 models.py:95 +msgid "Rejected" +msgstr "" + +#: actions.py:94 actions.py:165 +msgid "One selected transaction has been marked as rejected." +msgstr "" + +#: actions.py:95 actions.py:166 +#, python-format +msgid "%s selected transactions have been marked as rejected." +msgstr "" + +#: actions.py:99 +msgid "Mark as rejected" +msgstr "" + +#: actions.py:133 +msgid "One selected process has been marked as executed." +msgstr "" + +#: actions.py:134 +#, python-format +msgid "%s selected processes have been marked as executed." +msgstr "" + +#: actions.py:146 models.py:162 +msgid "Aborted" +msgstr "" + +#: actions.py:149 +msgid "One selected process has been aborted." +msgstr "" + +#: actions.py:150 +#, python-format +msgid "%s selected processes have been aborted." +msgstr "" + +#: actions.py:154 +msgid "Abort" +msgstr "" + +#: actions.py:170 +msgid "Commit" +msgstr "" + +#: admin.py:42 +msgid "ID" +msgstr "" + +#: admin.py:101 +msgid "proc" +msgstr "" + +#: admin.py:152 +msgid "Transactions" +msgstr "" + +#: methods/creditcard.py:11 +msgid "Label" +msgstr "" + +#: methods/creditcard.py:12 +msgid "Use a name such as \"Jo's Visa\" to remember which card it is." +msgstr "" + +#: methods/creditcard.py:30 +msgid "Credit card" +msgstr "" + +#: methods/sepadirectdebit.py:23 methods/sepadirectdebit.py:30 +msgid "Name" +msgstr "" + +#: methods/sepadirectdebit.py:39 +msgid "SEPA Direct Debit" +msgstr "" + +#: methods/sepadirectdebit.py:48 +msgid "" +"This bill will be automatically charged to your bank account with IBAN " +"number
%s." +msgstr "" +"Aquesta factura es cobrarà automaticament en el teu compte bancari amb IBAN " +"
%s." + +#: models.py:19 +msgid "account" +msgstr "" + +#: models.py:21 +msgid "method" +msgstr "" + +#: models.py:23 models.py:166 +msgid "data" +msgstr "" + +#: models.py:24 +msgid "active" +msgstr "" + +#: models.py:91 +msgid "Waitting processing" +msgstr "" + +#: models.py:92 +msgid "Waitting execution" +msgstr "" + +#: models.py:98 +msgid "bill" +msgstr "" + +#: models.py:101 +msgid "source" +msgstr "" + +#: models.py:103 +msgid "process" +msgstr "" + +#: models.py:104 models.py:168 +msgid "state" +msgstr "" + +#: models.py:106 +msgid "amount" +msgstr "" + +#: models.py:108 models.py:169 +msgid "created" +msgstr "" + +#: models.py:109 +msgid "modified" +msgstr "" + +#: models.py:124 +msgid "New transactions can not be allocated for this bill." +msgstr "" + +#: models.py:160 +msgid "Created" +msgstr "" + +#: models.py:163 +msgid "Commited" +msgstr "" + +#: models.py:167 +msgid "file" +msgstr "" + +#: models.py:170 +msgid "updated" +msgstr "" + +#: models.py:173 +msgid "Transaction processes" +msgstr "" diff --git a/orchestra/contrib/payments/locale/es/LC_MESSAGES/django.mo b/orchestra/contrib/payments/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..ae58b2d019a751ec0c4d9057acb695dbb9316e3e GIT binary patch literal 645 zcmZ{h&u-H|5XKEE7auuu7$lHDWm6}jC~};rZsHUR{|Sy$2~Mn?jkB%28||*4c@Q3e zx8Tlu@GOkeig4kRe(M?O8~gLl@24lnA?HATMwL z+rR4O56ZV(L&57BzI8{zfVM_9)bNtl^&ZMCRTW!H~X4Ehj22TH+IOk+Ag#J7Ct#j(2&`2`&m3J?H@O=vW zjKnFK`S3n<kR z<#RGT`np&frbr-4x#psBVOVfuFX~p&n#`qYv, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-05-28 16:40+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: actions.py:21 +msgid "Selected transactions must be on '{state}' state" +msgstr "" + +#: actions.py:30 +msgid "Processed" +msgstr "" + +#: actions.py:37 +msgid "Selected transaction has been processed." +msgstr "" + +#: actions.py:38 +#, python-format +msgid "%s Selected transactions have been processed." +msgstr "" + +#: actions.py:41 +msgid "" +"The following transaction process has been generated, you may want to save " +"it on your computer now." +msgstr "" + +#: actions.py:43 +#, python-format +msgid "" +"The following %s transaction processes have been generated, you may want to " +"save it on your computer now." +msgstr "" + +#: actions.py:46 +msgid "Process" +msgstr "" + +#: actions.py:59 actions.py:130 models.py:93 models.py:161 +msgid "Executed" +msgstr "" + +#: actions.py:62 +msgid "One selected transaction has been marked as executed." +msgstr "" + +#: actions.py:63 +#, python-format +msgid "%s selected transactions have been marked as executed." +msgstr "" + +#: actions.py:67 actions.py:138 +msgid "Mark as executed" +msgstr "" + +#: actions.py:75 models.py:94 +msgid "Secured" +msgstr "" + +#: actions.py:78 +msgid "One selected transaction has been marked as secured." +msgstr "" + +#: actions.py:79 +#, python-format +msgid "%s selected transactions have been marked as secured." +msgstr "" + +#: actions.py:83 +msgid "Mark as secured" +msgstr "" + +#: actions.py:91 actions.py:162 models.py:95 +msgid "Rejected" +msgstr "" + +#: actions.py:94 actions.py:165 +msgid "One selected transaction has been marked as rejected." +msgstr "" + +#: actions.py:95 actions.py:166 +#, python-format +msgid "%s selected transactions have been marked as rejected." +msgstr "" + +#: actions.py:99 +msgid "Mark as rejected" +msgstr "" + +#: actions.py:133 +msgid "One selected process has been marked as executed." +msgstr "" + +#: actions.py:134 +#, python-format +msgid "%s selected processes have been marked as executed." +msgstr "" + +#: actions.py:146 models.py:162 +msgid "Aborted" +msgstr "" + +#: actions.py:149 +msgid "One selected process has been aborted." +msgstr "" + +#: actions.py:150 +#, python-format +msgid "%s selected processes have been aborted." +msgstr "" + +#: actions.py:154 +msgid "Abort" +msgstr "" + +#: actions.py:170 +msgid "Commit" +msgstr "" + +#: admin.py:42 +msgid "ID" +msgstr "" + +#: admin.py:101 +msgid "proc" +msgstr "" + +#: admin.py:152 +msgid "Transactions" +msgstr "" + +#: methods/creditcard.py:11 +msgid "Label" +msgstr "" + +#: methods/creditcard.py:12 +msgid "Use a name such as \"Jo's Visa\" to remember which card it is." +msgstr "" + +#: methods/creditcard.py:30 +msgid "Credit card" +msgstr "" + +#: methods/sepadirectdebit.py:23 methods/sepadirectdebit.py:30 +msgid "Name" +msgstr "" + +#: methods/sepadirectdebit.py:39 +msgid "SEPA Direct Debit" +msgstr "" + +#: methods/sepadirectdebit.py:48 +msgid "" +"This bill will be automatically charged to your bank account with IBAN " +"number
%s." +msgstr "" +"Esta factura se cobrará automaticamente en tu cuenta bancaria con IBAN " +"
%s." + +#: models.py:19 +msgid "account" +msgstr "" + +#: models.py:21 +msgid "method" +msgstr "" + +#: models.py:23 models.py:166 +msgid "data" +msgstr "" + +#: models.py:24 +msgid "active" +msgstr "" + +#: models.py:91 +msgid "Waitting processing" +msgstr "" + +#: models.py:92 +msgid "Waitting execution" +msgstr "" + +#: models.py:98 +msgid "bill" +msgstr "" + +#: models.py:101 +msgid "source" +msgstr "" + +#: models.py:103 +msgid "process" +msgstr "" + +#: models.py:104 models.py:168 +msgid "state" +msgstr "" + +#: models.py:106 +msgid "amount" +msgstr "" + +#: models.py:108 models.py:169 +msgid "created" +msgstr "" + +#: models.py:109 +msgid "modified" +msgstr "" + +#: models.py:124 +msgid "New transactions can not be allocated for this bill." +msgstr "" + +#: models.py:160 +msgid "Created" +msgstr "" + +#: models.py:163 +msgid "Commited" +msgstr "" + +#: models.py:167 +msgid "file" +msgstr "" + +#: models.py:170 +msgid "updated" +msgstr "" + +#: models.py:173 +msgid "Transaction processes" +msgstr "" diff --git a/orchestra/contrib/payments/methods/sepadirectdebit.py b/orchestra/contrib/payments/methods/sepadirectdebit.py index 5d871926..52706ad0 100644 --- a/orchestra/contrib/payments/methods/sepadirectdebit.py +++ b/orchestra/contrib/payments/methods/sepadirectdebit.py @@ -45,7 +45,7 @@ class SEPADirectDebit(PaymentMethod): due_delta = datetime.timedelta(days=5) def get_bill_message(self): - return _("This bill will been automatically charged to your bank account " + return _("This bill will be automatically charged to your bank account " " with IBAN number
%s.") % self.instance.number @classmethod @@ -211,7 +211,7 @@ class SEPADirectDebit(PaymentMethod): ), E.DbtrAcct( # Debtor Account E.Id( - E.IBAN(data['iban']) + E.IBAN(data['iban'].replace(' ', '')) ), ), ) @@ -246,7 +246,7 @@ class SEPADirectDebit(PaymentMethod): ), E.CdtrAcct( # Creditor Account E.Id( - E.IBAN(data['iban']) + E.IBAN(data['iban'].replace(' ', '')) ), ), ) @@ -279,7 +279,8 @@ class SEPADirectDebit(PaymentMethod): xsd_path = os.path.join(path, xsd) schema_doc = etree.parse(xsd_path) schema = etree.XMLSchema(schema_doc) - sepa = etree.parse(StringIO(etree.tostring(sepa))) + sepa = StringIO(etree.tostring(sepa).decode('utf8')) + sepa = etree.parse(sepa) schema.assertValid(sepa) process.file = file_name process.save(update_fields=['file']) diff --git a/orchestra/contrib/payments/models.py b/orchestra/contrib/payments/models.py index 79ce714a..aba33cfb 100644 --- a/orchestra/contrib/payments/models.py +++ b/orchestra/contrib/payments/models.py @@ -99,7 +99,7 @@ class Transaction(models.Model): related_name='transactions') source = models.ForeignKey(PaymentSource, null=True, blank=True, verbose_name=_("source"), related_name='transactions') - process = models.ForeignKey('payments.TransactionProcess', null=True, + process = models.ForeignKey('payments.TransactionProcess', null=True, on_delete=models.SET_NULL, blank=True, verbose_name=_("process"), related_name='transactions') state = models.CharField(_("state"), max_length=32, choices=STATES, default=WAITTING_PROCESSING) @@ -111,7 +111,7 @@ class Transaction(models.Model): objects = TransactionQuerySet.as_manager() def __str__(self): - return "Transaction #{}".format(self.id) + return "#%i" % self.id @property def account(self): diff --git a/orchestra/contrib/payments/templates/admin/payments/transaction/get_processes.html b/orchestra/contrib/payments/templates/admin/payments/transaction/get_processes.html index 05c2f8a7..d3bb7b74 100644 --- a/orchestra/contrib/payments/templates/admin/payments/transaction/get_processes.html +++ b/orchestra/contrib/payments/templates/admin/payments/transaction/get_processes.html @@ -6,7 +6,7 @@

{{ content_message }}

    {% for proc in processes %} -
  • Process #{{ proc.id }} +
  • Process #{{ proc.id }} {% if proc.file %} {% endif %} diff --git a/orchestra/contrib/systemusers/actions.py b/orchestra/contrib/systemusers/actions.py index 51e03864..0fb90eb4 100644 --- a/orchestra/contrib/systemusers/actions.py +++ b/orchestra/contrib/systemusers/actions.py @@ -94,4 +94,3 @@ def delete_selected(modeladmin, request, queryset): return return admin.actions.delete_selected(modeladmin, request, queryset) delete_selected.short_description = _("Delete selected %(verbose_name_plural)s") - diff --git a/orchestra/contrib/systemusers/admin.py b/orchestra/contrib/systemusers/admin.py index c0fa6cf4..7e2957e6 100644 --- a/orchestra/contrib/systemusers/admin.py +++ b/orchestra/contrib/systemusers/admin.py @@ -41,8 +41,8 @@ class SystemUserAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, Extende add_form = SystemUserCreationForm form = SystemUserChangeForm ordering = ('-id',) - actions = (delete_selected, set_permission, disable) - change_view_actions = actions + change_view_actions = (set_permission, disable) + actions = (delete_selected,) + change_view_actions def display_main(self, user): return user.is_main diff --git a/orchestra/contrib/systemusers/models.py b/orchestra/contrib/systemusers/models.py index 29419b83..fb274a78 100644 --- a/orchestra/contrib/systemusers/models.py +++ b/orchestra/contrib/systemusers/models.py @@ -31,10 +31,10 @@ class SystemUser(models.Model): """ System users - Username max_length determined by LINUX system user lentgh: 32 + Username max_length determined by LINUX system user/group lentgh: 32 """ username = models.CharField(_("username"), max_length=32, unique=True, - help_text=_("Required. 64 characters or fewer. Letters, digits and ./-/_ only."), + help_text=_("Required. 32 characters or fewer. Letters, digits and ./-/_ only."), validators=[validators.validate_username]) password = models.CharField(_("password"), max_length=128) account = models.ForeignKey('accounts.Account', verbose_name=_("Account"), diff --git a/orchestra/utils/html.py b/orchestra/utils/html.py index 6d84a52d..6d6731d3 100644 --- a/orchestra/utils/html.py +++ b/orchestra/utils/html.py @@ -7,7 +7,6 @@ def html_to_pdf(html, pagination=False): """ converts HTL to PDF using wkhtmltopdf """ context = { 'pagination': textwrap.dedent("""\ - --footer-center "Page [page] of [topage]"\\ --footer-center "Page [page] of [topage]" \\ --footer-font-name sans \\ --footer-font-size 7 \\ @@ -20,6 +19,6 @@ def html_to_pdf(html, pagination=False): --use-xserver \\ %(pagination)s \\ --margin-bottom 22 \\ - --margin-top 20 - -\ + --margin-top 20 - - \ """) % context return run(cmd, stdin=html.encode('utf-8')).stdout diff --git a/orchestra/utils/mail.py b/orchestra/utils/mail.py index 21028fb9..e4c925a4 100644 --- a/orchestra/utils/mail.py +++ b/orchestra/utils/mail.py @@ -15,8 +15,6 @@ def render_email_template(template, context): """ if isinstance(context, dict): context = Context(context) - if isinstance(to, str): - to = [to] if not 'site' in context: from orchestra import settings @@ -32,6 +30,8 @@ def render_email_template(template, context): def send_email_template(template, context, to, email_from=None, html=None, attachments=[]): + if isinstance(to, str): + to = [to] subject, message = render_email_template(template, context) msg = EmailMultiAlternatives(subject, message, email_from, to, attachments=attachments) if html: diff --git a/requirements.txt b/requirements.txt index 7547422c..a3e0d8bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ celery==3.1.16 kombu==3.0.23 billiard==3.3.0.18 Markdown==2.4 -djangorestframework==3.1.1 +djangorestframework==3.1.2 ecdsa==0.11 Pygments==1.6 django-filter==0.7