From 8959bc6ad5f7517923b1fb5ab4b110bd7dad5a65 Mon Sep 17 00:00:00 2001 From: Nico Schottelius Date: Sun, 25 Oct 2020 13:52:36 +0100 Subject: [PATCH] various updates --- .../0005_uncloudprovider_coupon_network.py | 21 ++++++++ uncloud/models.py | 4 +- uncloud_net/models.py | 3 +- .../migrations/0035_auto_20201012_1728.py | 48 +++++++++++++++++++ uncloud_pay/models.py | 28 +++++++++-- uncloud_pay/templates/bill.html.j2 | 8 ++-- uncloud_pay/views.py | 1 + 7 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 uncloud/migrations/0005_uncloudprovider_coupon_network.py create mode 100644 uncloud_pay/migrations/0035_auto_20201012_1728.py diff --git a/uncloud/migrations/0005_uncloudprovider_coupon_network.py b/uncloud/migrations/0005_uncloudprovider_coupon_network.py new file mode 100644 index 0000000..b74b878 --- /dev/null +++ b/uncloud/migrations/0005_uncloudprovider_coupon_network.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1 on 2020-10-12 17:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_net', '0010_auto_20201011_2009'), + ('uncloud', '0004_auto_20201011_2031'), + ] + + operations = [ + migrations.AddField( + model_name='uncloudprovider', + name='coupon_network', + field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, related_name='uncloudprovidercoupon', to='uncloud_net.uncloudnetwork'), + preserve_default=False, + ), + ] diff --git a/uncloud/models.py b/uncloud/models.py index 680e166..623d144 100644 --- a/uncloud/models.py +++ b/uncloud/models.py @@ -87,6 +87,7 @@ class UncloudProvider(UncloudAddress): billing_network = models.ForeignKey(UncloudNetwork, related_name="uncloudproviderbill", on_delete=models.CASCADE) referral_network = models.ForeignKey(UncloudNetwork, related_name="uncloudproviderreferral", on_delete=models.CASCADE) + coupon_network = models.ForeignKey(UncloudNetwork, related_name="uncloudprovidercoupon", on_delete=models.CASCADE) @classmethod @@ -112,7 +113,8 @@ class UncloudProvider(UncloudAddress): country="CH", starting_date=timezone.now(), billing_network=UncloudNetwork.objects.get(description="uncloud Billing"), - referral_network=UncloudNetwork.objects.get(description="uncloud Referral") + referral_network=UncloudNetwork.objects.get(description="uncloud Referral"), + coupon_network=UncloudNetwork.objects.get(description="uncloud Coupon") ) diff --git a/uncloud_net/models.py b/uncloud_net/models.py index a01dcc5..e4e1bb1 100644 --- a/uncloud_net/models.py +++ b/uncloud_net/models.py @@ -23,7 +23,8 @@ class UncloudNetwork(models.Model): def populate_db_defaults(cls): for net, desc in [ ( "2a0a:e5c0:11::", "uncloud Billing" ), - ( "2a0a:e5c0:11:1::", "uncloud Referral" ) + ( "2a0a:e5c0:11:1::", "uncloud Referral" ), + ( "2a0a:e5c0:11:2::", "uncloud Coupon" ) ]: obj, created = cls.objects.get_or_create(network_address=net, defaults= { diff --git a/uncloud_pay/migrations/0035_auto_20201012_1728.py b/uncloud_pay/migrations/0035_auto_20201012_1728.py new file mode 100644 index 0000000..af30d98 --- /dev/null +++ b/uncloud_pay/migrations/0035_auto_20201012_1728.py @@ -0,0 +1,48 @@ +# Generated by Django 3.1 on 2020-10-12 17:28 + +from django.db import migrations, models +import uncloud.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_pay', '0034_auto_20201011_2031'), + ] + + operations = [ + migrations.AddField( + model_name='billingaddress', + name='city', + field=models.CharField(default='', max_length=256), + preserve_default=False, + ), + migrations.AddField( + model_name='billingaddress', + name='country', + field=uncloud.models.CountryField(blank=True, choices=[('AD', 'Andorra'), ('AE', 'United Arab Emirates'), ('AF', 'Afghanistan'), ('AG', 'Antigua & Barbuda'), ('AI', 'Anguilla'), ('AL', 'Albania'), ('AM', 'Armenia'), ('AN', 'Netherlands Antilles'), ('AO', 'Angola'), ('AQ', 'Antarctica'), ('AR', 'Argentina'), ('AS', 'American Samoa'), ('AT', 'Austria'), ('AU', 'Australia'), ('AW', 'Aruba'), ('AZ', 'Azerbaijan'), ('BA', 'Bosnia and Herzegovina'), ('BB', 'Barbados'), ('BD', 'Bangladesh'), ('BE', 'Belgium'), ('BF', 'Burkina Faso'), ('BG', 'Bulgaria'), ('BH', 'Bahrain'), ('BI', 'Burundi'), ('BJ', 'Benin'), ('BM', 'Bermuda'), ('BN', 'Brunei Darussalam'), ('BO', 'Bolivia'), ('BR', 'Brazil'), ('BS', 'Bahama'), ('BT', 'Bhutan'), ('BV', 'Bouvet Island'), ('BW', 'Botswana'), ('BY', 'Belarus'), ('BZ', 'Belize'), ('CA', 'Canada'), ('CC', 'Cocos (Keeling) Islands'), ('CF', 'Central African Republic'), ('CG', 'Congo'), ('CH', 'Switzerland'), ('CI', 'Ivory Coast'), ('CK', 'Cook Iislands'), ('CL', 'Chile'), ('CM', 'Cameroon'), ('CN', 'China'), ('CO', 'Colombia'), ('CR', 'Costa Rica'), ('CU', 'Cuba'), ('CV', 'Cape Verde'), ('CX', 'Christmas Island'), ('CY', 'Cyprus'), ('CZ', 'Czech Republic'), ('DE', 'Germany'), ('DJ', 'Djibouti'), ('DK', 'Denmark'), ('DM', 'Dominica'), ('DO', 'Dominican Republic'), ('DZ', 'Algeria'), ('EC', 'Ecuador'), ('EE', 'Estonia'), ('EG', 'Egypt'), ('EH', 'Western Sahara'), ('ER', 'Eritrea'), ('ES', 'Spain'), ('ET', 'Ethiopia'), ('FI', 'Finland'), ('FJ', 'Fiji'), ('FK', 'Falkland Islands (Malvinas)'), ('FM', 'Micronesia'), ('FO', 'Faroe Islands'), ('FR', 'France'), ('FX', 'France, Metropolitan'), ('GA', 'Gabon'), ('GB', 'United Kingdom (Great Britain)'), ('GD', 'Grenada'), ('GE', 'Georgia'), ('GF', 'French Guiana'), ('GH', 'Ghana'), ('GI', 'Gibraltar'), ('GL', 'Greenland'), ('GM', 'Gambia'), ('GN', 'Guinea'), ('GP', 'Guadeloupe'), ('GQ', 'Equatorial Guinea'), ('GR', 'Greece'), ('GS', 'South Georgia and the South Sandwich Islands'), ('GT', 'Guatemala'), ('GU', 'Guam'), ('GW', 'Guinea-Bissau'), ('GY', 'Guyana'), ('HK', 'Hong Kong'), ('HM', 'Heard & McDonald Islands'), ('HN', 'Honduras'), ('HR', 'Croatia'), ('HT', 'Haiti'), ('HU', 'Hungary'), ('ID', 'Indonesia'), ('IE', 'Ireland'), ('IL', 'Israel'), ('IN', 'India'), ('IO', 'British Indian Ocean Territory'), ('IQ', 'Iraq'), ('IR', 'Islamic Republic of Iran'), ('IS', 'Iceland'), ('IT', 'Italy'), ('JM', 'Jamaica'), ('JO', 'Jordan'), ('JP', 'Japan'), ('KE', 'Kenya'), ('KG', 'Kyrgyzstan'), ('KH', 'Cambodia'), ('KI', 'Kiribati'), ('KM', 'Comoros'), ('KN', 'St. Kitts and Nevis'), ('KP', "Korea, Democratic People's Republic of"), ('KR', 'Korea, Republic of'), ('KW', 'Kuwait'), ('KY', 'Cayman Islands'), ('KZ', 'Kazakhstan'), ('LA', "Lao People's Democratic Republic"), ('LB', 'Lebanon'), ('LC', 'Saint Lucia'), ('LI', 'Liechtenstein'), ('LK', 'Sri Lanka'), ('LR', 'Liberia'), ('LS', 'Lesotho'), ('LT', 'Lithuania'), ('LU', 'Luxembourg'), ('LV', 'Latvia'), ('LY', 'Libyan Arab Jamahiriya'), ('MA', 'Morocco'), ('MC', 'Monaco'), ('MD', 'Moldova, Republic of'), ('MG', 'Madagascar'), ('MH', 'Marshall Islands'), ('ML', 'Mali'), ('MN', 'Mongolia'), ('MM', 'Myanmar'), ('MO', 'Macau'), ('MP', 'Northern Mariana Islands'), ('MQ', 'Martinique'), ('MR', 'Mauritania'), ('MS', 'Monserrat'), ('MT', 'Malta'), ('MU', 'Mauritius'), ('MV', 'Maldives'), ('MW', 'Malawi'), ('MX', 'Mexico'), ('MY', 'Malaysia'), ('MZ', 'Mozambique'), ('NA', 'Namibia'), ('NC', 'New Caledonia'), ('NE', 'Niger'), ('NF', 'Norfolk Island'), ('NG', 'Nigeria'), ('NI', 'Nicaragua'), ('NL', 'Netherlands'), ('NO', 'Norway'), ('NP', 'Nepal'), ('NR', 'Nauru'), ('NU', 'Niue'), ('NZ', 'New Zealand'), ('OM', 'Oman'), ('PA', 'Panama'), ('PE', 'Peru'), ('PF', 'French Polynesia'), ('PG', 'Papua New Guinea'), ('PH', 'Philippines'), ('PK', 'Pakistan'), ('PL', 'Poland'), ('PM', 'St. Pierre & Miquelon'), ('PN', 'Pitcairn'), ('PR', 'Puerto Rico'), ('PT', 'Portugal'), ('PW', 'Palau'), ('PY', 'Paraguay'), ('QA', 'Qatar'), ('RE', 'Reunion'), ('RO', 'Romania'), ('RU', 'Russian Federation'), ('RW', 'Rwanda'), ('SA', 'Saudi Arabia'), ('SB', 'Solomon Islands'), ('SC', 'Seychelles'), ('SD', 'Sudan'), ('SE', 'Sweden'), ('SG', 'Singapore'), ('SH', 'St. Helena'), ('SI', 'Slovenia'), ('SJ', 'Svalbard & Jan Mayen Islands'), ('SK', 'Slovakia'), ('SL', 'Sierra Leone'), ('SM', 'San Marino'), ('SN', 'Senegal'), ('SO', 'Somalia'), ('SR', 'Suriname'), ('ST', 'Sao Tome & Principe'), ('SV', 'El Salvador'), ('SY', 'Syrian Arab Republic'), ('SZ', 'Swaziland'), ('TC', 'Turks & Caicos Islands'), ('TD', 'Chad'), ('TF', 'French Southern Territories'), ('TG', 'Togo'), ('TH', 'Thailand'), ('TJ', 'Tajikistan'), ('TK', 'Tokelau'), ('TM', 'Turkmenistan'), ('TN', 'Tunisia'), ('TO', 'Tonga'), ('TP', 'East Timor'), ('TR', 'Turkey'), ('TT', 'Trinidad & Tobago'), ('TV', 'Tuvalu'), ('TW', 'Taiwan, Province of China'), ('TZ', 'Tanzania, United Republic of'), ('UA', 'Ukraine'), ('UG', 'Uganda'), ('UM', 'United States Minor Outlying Islands'), ('US', 'United States of America'), ('UY', 'Uruguay'), ('UZ', 'Uzbekistan'), ('VA', 'Vatican City State (Holy See)'), ('VC', 'St. Vincent & the Grenadines'), ('VE', 'Venezuela'), ('VG', 'British Virgin Islands'), ('VI', 'United States Virgin Islands'), ('VN', 'Viet Nam'), ('VU', 'Vanuatu'), ('WF', 'Wallis & Futuna Islands'), ('WS', 'Samoa'), ('YE', 'Yemen'), ('YT', 'Mayotte'), ('YU', 'Yugoslavia'), ('ZA', 'South Africa'), ('ZM', 'Zambia'), ('ZR', 'Zaire'), ('ZW', 'Zimbabwe')], default='CH', max_length=2), + ), + migrations.AddField( + model_name='billingaddress', + name='full_name', + field=models.CharField(default='', max_length=256), + preserve_default=False, + ), + migrations.AddField( + model_name='billingaddress', + name='organization', + field=models.CharField(blank=True, max_length=256, null=True), + ), + migrations.AddField( + model_name='billingaddress', + name='postal_code', + field=models.CharField(default='', max_length=64), + preserve_default=False, + ), + migrations.AddField( + model_name='billingaddress', + name='street', + field=models.CharField(default='', max_length=256), + preserve_default=False, + ), + ] diff --git a/uncloud_pay/models.py b/uncloud_pay/models.py index 3648795..5bff5a3 100644 --- a/uncloud_pay/models.py +++ b/uncloud_pay/models.py @@ -263,7 +263,7 @@ class RecurringPeriod(models.Model): ### # Bills. -class BillingAddress(models.Model): +class BillingAddress(UncloudAddress): owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) vat_number = models.CharField(max_length=100, default="", blank=True) active = models.BooleanField(default=False) @@ -300,7 +300,6 @@ class BillingAddress(models.Model): active=True) - @staticmethod def get_address_for(user): return BillingAddress.objects.get(owner=user, active=True) @@ -308,7 +307,7 @@ class BillingAddress(models.Model): def __str__(self): return "{} - {}, {}, {} {}, {}".format( self.owner, - self.name, self.street, self.postal_code, self.city, + self.full_name, self.street, self.postal_code, self.city, self.country) ### @@ -1059,7 +1058,21 @@ class Bill(models.Model): - If the customer is outside EU and outside CH -> do not apply VAT """ - provider_country = UncloudProvider.objects.get() + provider = UncloudProvider.objects.get() + + # Assume always VAT inside the country + if provider.country = self.billing_address.country: + vat_rate = VATRate.objects.get(country=provider.country, + when=self.ending_date) + elif self.billing_address.country in EU: + # FIXME: need to check for validated vat number + if self.billing_address.vat_number: + return 0 + else: + return VATRate.objects.get(country=self.biling_address.country, + when=self.ending_date) + else: # non-EU, non-national + return 0 @classmethod @@ -1182,6 +1195,13 @@ class BillRecord(models.Model): else: return self.order.one_time_price + @property + def price(self): + if self.is_recurring_record: + return self.order.recurring_price + else: + return self.order.one_time_price + def __str__(self): if self.is_recurring_record: bill_line = f"{self.starting_date} - {self.ending_date}: {self.quantity} x {self.order}" diff --git a/uncloud_pay/templates/bill.html.j2 b/uncloud_pay/templates/bill.html.j2 index e3238d3..c227f43 100644 --- a/uncloud_pay/templates/bill.html.j2 +++ b/uncloud_pay/templates/bill.html.j2 @@ -6,7 +6,7 @@ Icons, fonts, etc. are INLINED. This is rather ugly, but as the PDF generation is based on a local snapshot of the HTML file, URLs are - screwed if they are not absolute. + screwed if they are not absolute to the *local* filesystem. As this document is used ONLY for bills and ONLY for downloading, I decided that this is an acceptable uglyness. @@ -695,9 +695,9 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7 Detail - Units Price/Unit - Total price + Units + Total price @@ -707,8 +707,8 @@ oAsAAAAAAACGQNAFAAAAAAAAQyDoAgAAAAAAgCEQdAEAAAAAAMAQCLoAAAAAAABgCP83AL6WQ1Y7 - {{ record.ending_date|date:"c" }} {{ record.order }} + {{ record.price|floatformat:2 }} {{ record.quantity|floatformat:2 }} - {{ record.order.price|floatformat:2 }} {{ record.sum|floatformat:2 }} {% endfor %} diff --git a/uncloud_pay/views.py b/uncloud_pay/views.py index 9ca3bcf..edfb189 100644 --- a/uncloud_pay/views.py +++ b/uncloud_pay/views.py @@ -201,6 +201,7 @@ class BillViewSet(viewsets.ReadOnlyModelViewSet): Allow to download """ bill = self.get_object() + provider = UncloudProvider.get_provider() output_file = NamedTemporaryFile() bill_html = render_to_string("bill.html.j2", {'bill': bill})