def test_report_unknown_service(self): prepay_entity_customer = {"customer_type": "entity", "detailed_info": { "name": "test prepay entity customer", "contract_number": "2015/4568", "contract_date": "2015-01-01", "organization_type": "OOO", "name": "Some Company", "full_organization_name": "OOO Some Company", "primary_state_registration_number": "159 8525 15552", "individual_tax_number": "52 59 5555555", "legal_address_country": "RU", "legal_address_city": "NN", "legal_address_address": "Ошарская, 13", "location_country": "RU", "location_city": "NN", "location_address": "Ошарская", "general_manager_name": "Васильев Е.В", "general_accountant_name": "Иванова В.Н", "contact_person_name": "Петров Василий" }} self.create_tariff("First Tariff", default=True) customer_info = self.create_customer("*****@*****.**", **prepay_entity_customer) customer_id = customer_info["customer_id"] customer = Customer.get_by_id(customer_id) tenant = Tenant.create(uuid.uuid4().hex, "test tenant") tenant_id = tenant.tenant_id customer.confirm_email() # clear db session customer.os_tenant_id = tenant_id db.session.commit() start = datetime(2015, 4, 1) end = datetime(2015, 4, 1, 10) - timedelta(seconds=1) customer = Customer.get_by_id(customer_id) Customer.fake_usage(customer, start, end, "service_unknown", "unknown resource", 1) db.session.commit() report = self.get_customer_report(customer_id, start, end, "pdf", filename="unknown_service.pdf") self.assertTrue(report) report = self.get_customer_report(customer_id, start, end, "pdf", filename="unknown_service_detailed.pdf", report_type="detailed") self.assertTrue(report)
def task_os_create_tenant_and_user(customer_id, email): # email is just for logs customer = Customer.get_by_id(customer_id) log.debug("task_os_create_tenant_and_user: {}", customer) if not customer: log.warning("Can't find customer {} {}. Possible customer was removed by system test", customer_id, email) return info = openstack.create_tenant_and_user(email, customer_id, customer.tariff.flavors(), password=customer.os_user_password, enabled=True) log.debug("Openstack info: {}", info) # Tests can delete customer already here, therefore no updates are required if not conf.test: db.session.commit() db.session.close() customer = Customer.get_by_id(customer_id) if customer: customer.update_os_credentials(info['tenant_id'], info['tenant_name'], info['user_id'], info["username"], info['password']) send_email_os_credentials(info['email'], info['name'], info['password'], info['tenant_id'], language=customer.locale_language()) db.session.commit() else: final_delete_from_os(info['tenant_id'], info['user_id'])
def update_quota(customer_id, user_id, quotas): from model import Customer, CustomerHistory customer = Customer.get_by_id(customer_id) if not customer: logbook.warning("Customer id '{}' not found for quota update", customer_id) return customer = Customer.get_by_id(customer_id) openstack.change_tenant_quotas(customer.os_tenant_id, **quotas) CustomerHistory.quota_changed(customer, user_id, None)
def test_collector_sequence(self): start_time = datetime.datetime(2015, 3, 20, 9, 12) end_time = datetime.datetime(2015, 3, 21) project = Tenant("boss", start_time) disk = Disk(project, "test_disk", start_time, 1234567890) hour_price = Decimal(self.image_size_price)*2 t = start_time count = 0 while t < end_time: disk.repeat_message(t, t + datetime.timedelta(hours=1)) with mock.patch("os_interfaces.openstack_wrapper.openstack") as openstack: openstack.get_tenant_usage = project.usage project.prepare_messages() tenants_usage = self.collector.run_usage_collection(t + datetime.timedelta(hours=1, minutes=10)) self.assertTrue(tenants_usage[project.project_id]) t += datetime.timedelta(hours=1) count += 1 account = Customer.get_by_id(project.customer_id).account_dict()["RUB"] hours = int((end_time - start_time).total_seconds() // 3600) + 1 total_cost = hours * hour_price self.assertLess(abs(account["withdraw"] - total_cost), 0.0001)
def clean_up_customer_service_usage(self, customer_id, end_date): from model import Customer customer = Customer.get_by_id(customer_id) if not customer: logbook.warning("Customer id '{}' not found for cleaning up services usage", customer_id) return customer.clean_up_service_usage(end_date)
def aggregate(self, report_id): logbook.info("Get customer usage aggregation for {}", report_id) customer = Customer.get_by_id(report_id.customer_id) if not customer: raise Exception("Customer %s not found" % report_id.customer_id) with timed("get_usage simple"): aggregated_usage = ServiceUsage.get_usage(customer, report_id.start, report_id.end) tariffs = {} services = set() for usage in aggregated_usage: service_id, tariff_id, cost, usage_volume = usage services.add(service_id) if not tariff_id: logbook.error("ServiceUsage {} is not completed. Tariff is not filled", usage) continue tariff = Tariff.get_by_id(tariff_id) tariff_report = tariffs.get(tariff_id) if tariff_report is None: tariff_report = self.tariff_report_type(tariff, customer) tariffs[tariff_id] = tariff_report tariff_report.add_usage(usage) total = Counter() for tariff_id, tariff in tariffs.items(): total_tariff, currency = tariff.aggregate() total[currency] += total_tariff for t, value in total.items(): total[t] = decimal_to_string(value) logbook.info("Aggregated {} for {}. Services: {}", total, customer, services) return self.prepare_result(list(tariffs.values()), total, customer, report_id.start, report_id.end)
def get_used_quotas(customer_id): from model import Customer customer = Customer.get_by_id(customer_id) if not customer: logbook.warning("Customer id '{}' not found for getting used quotas", customer_id) return customer.get_used_quotas()
def test_publish(self): Tariff.create_tariff(self.localized_name("tariff_for_balance"), "tariff!!!", "rub", None) customer_id = Customer.new_customer("*****@*****.**", "123qwe", self.admin_user.user_id).customer_id db.session.commit() customer = Customer.get_by_id(customer_id) news_id = self.admin_client.news.create(**self.test_news)['news_id'] # check publish news = self.admin_client.news.publish(news_id, publish=True) self.assertTrue(news['published']) self.assertEqual(outbox[0].to, [customer.email]) self.assertIn(self.test_news['subject'], outbox[0].subject) news_id = self.admin_client.news.create(subject='$test_subject', body='test_body')['news_id'] self.admin_client.news.publish(news_id, publish=True) self.assertEqual(len(outbox), 1) # check unpublish news = self.admin_client.news.publish(news_id, publish=False) self.assertFalse(news['published']) self.assertEqual(len(outbox), 1) # check publish deleted news self.admin_client.news.delete(news_id) with self.expect_error(errors.RemovedNews): self.admin_client.news.publish(news_id, publish=True)
def make_action(cls, state, now=None): from model import Customer logbook.info("Try apply action: {}", state) now = now or utcnow().datetime machine = cls.machines[state.name] customer = Customer.get_by_id(state.customer_id) try: new_state_name = getattr(machine, state.action)(customer) except Exception as e: logbook.error("action {} failed: {}", state, e) state.remove() db.session.commit() raise state.step += 1 if not new_state_name: if state.step >= len(machine.schedule): logbook.info("Actions {} are completed for {}", cls.name, customer) state.remove() db.session.commit() return new_state = machine.schedule[state.step] else: new_state = find_first(machine.schedule, lambda x: x[0] == new_state_name) if not new_state: state.remove() db.session.commit() raise Exception("Can't find new state %s for machine %s" % (new_state_name, cls.name)) state.action = new_state[0] state.scheduled_at = now + timedelta(seconds=new_state[1]) logbook.info("New action {} is scheduled", state)
def test_receipts_report(self): self.create_tariff("default_tariff", default=True) customer_info = self.create_customer_by_self("*****@*****.**") db.session.commit() customer_id = customer_info["customer_id"] self.admin_client.customer.update_balance(customer_id, "100", "test withdraw for test mode", "RUB") self.admin_client.customer.update(customer_id, detailed_info={"passport_series_number": "1234 567 890", "passport_issued_by": "UFMS Russia", "passport_issued_date": "2013-01-01"}) customer_db = Customer.get_by_id(customer_id) customer_db.confirm_email() self.admin_client.customer.make_prod(customer_id) self.admin_client.customer.update_balance(customer_id, "100", "test withdraw for prod mode", "RUB") start = utcnow().datetime - timedelta(days=30) end = utcnow().datetime + timedelta(hours=1) report = self.get_report("receipts", start, end, "csv") self.assertTrue(report) self.assertGreater(report.count(b";"), 5) report = [row for row in report.split(b"\r\n") if row] self.assertEqual(len(report), 2) # header + balance update after prod self.get_report("receipts", start, end, "tsv")
def payment_check(self, *args, **request_data): """Checks payment availability for customer Parameters must be sent as json object. :param Int TransactionId: Mandatory - System transaction number. :param Numeric Amount: Mandatory - Payment amount from widget. Dot as separator, two digits after dot. :param String Currency: Mandatory - Currency: RUB/USD/EUR/GBP from widget parameters. :param String InvoiceId: Not mandatory - Order number from widget parameters. :param String AccountId: Mandatory - Customer identifier from widget parameters. :param String SubscriptionId: Not mandatory - Subscription identifier from widget parameters (for recurrent payments). :param String Name: Not mandatory - Card holder name. :param String Email: Payer's e-mail :param DateTime: Mandatory - Payment creation date/time in UTC (yyyy-MM-dd HH:mm:ss). :param String IpAddress: Not mandatory - Payer IP-address :param String IpCountry: Not mandatory - Payer's country double-chars code (according to ISO3166-1) :param String IpCity: Not mandatory - Payer's city :param String IpRegion: Not mandatory - Payer's region. :param String IpDistrict: Not mandatory - Payer's district. :param String CardFirstSix: Mandatory - Credit card first 6 digits :param String CardLastFour: Mandatory - Credit card last 6 digits :param String CardType: Mandatory - Card payment system: Visa or MasterCard or Maestro :param String CardExpDate: Mandatory - Card expiration date MM/YY :param String Issuer: Not mandatory - Issuer bank name :param String IssuerBankCountry: Not mandatory - Issuer bank country double-char code (according to ISO3166-1) :param String Description: Not mandatory - Payment description from widget parameters. :param Json Data: Not mandatory - Any json-data from widget. :param Bit TestMode: Mandatory - Test mode flag (1 or 0) :param String Status: Mandatory - Payment status: Completed — for single-step, Authorized — for double-step. :return: Status code, looks like {'code': 0} """ logbook.info("[payment_check] Request info:{}", request_data) short_payment_info = dict([(key, request_data.get(key)) for key in PaymentsApi.payment_info_fields]) # Common validation validation_res, validation_info = self.validate_request(request_data, short_payment_info) if not validation_res: log_error("[payment_check] {} Payment info: {}", validation_info, short_payment_info) return {'code': self.ERROR_COMMON} # Currency validation currency = request_data['Currency'] if not currency or currency not in conf.currency.active: log_error("[payment_check] Invalid or incompatible currency: {}. Payment info: {}", currency, short_payment_info) return {'code': self.ERROR_COMMON} # Customer validation customer_id = request_data['AccountId'] customer = Customer.get_by_id(customer_id, False) if not customer: log_error("[payment_check] Customer {} not found. Payment info: {}", customer_id, short_payment_info) return {'code': self.ERROR_COMMON} if customer.is_test_mode(): # Payments in test mode is not allowed logbook.warning("[payment_check] Customer {} in test mode. Payment info {}", customer, short_payment_info) return {'code': self.ERROR_COMMON} return {'code': self.ERROR_OK}
def notify_managers_about_hdd(self, customer_id): customer = Customer.get_by_id(customer_id) if not customer: logbook.error("Customer {} not found in notify manager", customer_id) return logbook.info("notify manager about hdd for removing for customer {}", customer) from model.account.customer_history import CustomerHistory block_event = CustomerHistory.get_last_block_event(customer) send_email_hdd_notification(get_customers_manager(customer), block_event.date, customer.email)
def test_usage_report(self): self.create_tariff("default_tariff", default=True) customer_info = self.create_customer_by_self("*****@*****.**") customer = Customer.get_by_id(customer_info["customer_id"]) tenant = Tenant.create(uuid.uuid4().hex, "test tenant") customer.os_tenant_id = tenant.tenant_id db.session.commit() start = datetime(2015, 4, 1) end = datetime(2015, 4, 25) end_report = end + timedelta(hours=24) cost1 = Decimal(0) cost1 += Customer.fake_usage(customer, start, end, self.service_nano_id, uuid.uuid4().hex, 1) cost1 += Customer.fake_usage(customer, start + timedelta(days=5), end, self.service_micro_id, uuid.uuid4().hex, 1) cost1 += Customer.fake_usage(customer, start + timedelta(days=6), end, self.service_nano_id, uuid.uuid4().hex, 1) cost1 += Customer.fake_usage(customer, start, end, "storage.image", uuid.uuid4().hex, 60*conf.GIGA) customer2_info = self.create_customer("*****@*****.**") tenant2 = Tenant.create(uuid.uuid4().hex, "test tenant 2") customer2 = Customer.get_by_id(customer2_info["customer_id"]) customer2.os_tenant_id = tenant2.tenant_id cost2 = Customer.fake_usage(customer2, start, end, self.service_nano_id, uuid.uuid4().hex, 1) db.session.commit() report = self.get_report("usage", start, end_report, "csv", locale="en_us") self.assertTrue(report) report = [row.decode("ascii") for row in report.split(b"\r\n") if row] parsed_report = csv.reader(report) cust_1 = [row for row in parsed_report if row[0] == '*****@*****.**'] cust_1_cost = sum(Decimal(row[1]) for row in cust_1) parsed_report = csv.reader(report) cust_2 = [row for row in parsed_report if row[0] == '*****@*****.**'] cust_2_cost = sum(Decimal(row[1]) for row in cust_2) self.assertEqual(len(cust_2), 1) self.assertEqual(len(cust_1), 1) self.assertEqual(cust_1_cost, cost1) self.assertEqual(cust_2_cost, cost2)
def reset_user_password(customer_id): customer = Customer.get_by_id(customer_id) if not customer: log.warning("Can't find customer for reset user password {} {}. Possible customer was removed by system test", customer_id) return password = openstack.reset_user_password(customer.os_user_id) customer.update_os_password(password) send_email_os_credentials(customer.email, customer.os_username, password, customer.os_tenant_id, language=customer.locale_language())
def notify_managers_about_new_service_in_tariff(self, customer_id, flavor_name): customer = Customer.get_by_id(customer_id) if not customer: logbook.error("Customer {} not found in notify manager", customer_id) return logbook.info("notify manager about adding new service to tariff {}", customer.tariff.name) from api.admin.user import UserApi service_edit_url = urljoin(request_base_url(), posixpath.join(UserApi.ADMIN_FRONTEND_PATH, "tariffs", str(customer.tariff.tariff_id), "services")) customer_url = urljoin(request_base_url(), posixpath.join(UserApi.ADMIN_FRONTEND_PATH, "index", str(customer.customer_id), "info")) subject, body = MessageTemplate.get_rendered_message(MessageTemplate.NEW_SERVICE_IN_TARIFF, language=preferred_language(), account=customer.email, flavor_name=flavor_name, tariff=customer.tariff.name, customer_url=customer_url, service_edit_url=service_edit_url) logbook.info("Sending email notification to delete data of {}", customer.email) send_email.delay(get_customers_manager(customer), subject, body)
def main(): import docopt from model import Customer opt = docopt.docopt(__doc__) tenant_id = opt["--tenant"] customer_id = opt["--customer"] if customer_id: try: customer_id = int(customer_id) customer = Customer.get_by_id(customer_id) except ValueError: customer = Customer.get_by_email(customer_id) if not customer: logbook.warning("Customer {} not found", customer_id) return else: tenant_id = customer.tenant.tenant_id start = opt["--start"] end = opt["--end"] now = arrow.utcnow().date() start = arrow.get(start) if start else now - timedelta(minutes=15) end = arrow.get(end) if end else now metric = opt["--metric"] service = opt["--service"] if service: service_mapping = {data["service"]: name for name, data in conf.fitter.collection.meter_mappings.items()} if service not in service_mapping: logbook.warning("Service {} not found", service) return metric = service_mapping[service] samples = openstack.get_tenant_usage(tenant_id, metric, start, end, limit=int(opt["--limit"])) logbook.info("Found {} samples", len(samples)) for s in samples: pprint(s._info)
def test_report_with_two_tariffs(self): prepay_entity_customer = {"customer_type": "entity", "detailed_info": { "name": "test prepay entity customer", "contract_number": "2015/4568", "contract_date": "2015-01-01", "organization_type": "OOO", "name": "Some Company", "full_organization_name": "OOO Some Company", "primary_state_registration_number": "159 8525 15552", "individual_tax_number": "52 59 5555555", "legal_address_country": "RU", "legal_address_city": "NN", "legal_address_address": "Ошарская, 13", "location_country": "RU", "location_city": "NN", "location_address": "Ошарская", "general_manager_name": "Васильев Е.В", "general_accountant_name": "Иванова В.Н", "contact_person_name": "Петров Василий" }} self.create_tariff("First Tariff", default=True) customer_info = self.create_customer("*****@*****.**", **prepay_entity_customer) customer_id = customer_info["customer_id"] customer = Customer.get_by_id(customer_id) tenant = Tenant.create(uuid.uuid4().hex, "test tenant") tenant_id = tenant.tenant_id customer.os_tenant_id = tenant_id db.session.commit() start = datetime(2015, 4, 1) middle_end = datetime(2015, 4, 1, 15) - timedelta(seconds=1) end = datetime(2015, 4, 2) - timedelta(seconds=1) end_second = datetime(2015, 4, 3) - timedelta(seconds=1) end_report = end_second + timedelta(hours=24) vm_nano = uuid.uuid4().hex vm_small = uuid.uuid4().hex vm_nano2 = "nano2" storage_id = "disk1" Customer.fake_usage(customer, start, end, self.service_nano_id, vm_nano, 1, resource_name="nano1") Customer.fake_usage(customer, start, end, self.service_small_id, vm_small, 1, resource_name="my little pony") Customer.fake_usage(customer, start, middle_end , self.service_nano_id, vm_nano2, 1, resource_name="pico") Customer.fake_usage(customer, start, middle_end, "storage.volume", storage_id, 1237852421) Customer.fake_usage(customer, middle_end + timedelta(hours=1), end, "storage.volume", storage_id, 77777777777) Customer.fake_usage(customer, start, end, "net.allocated_ip", "ip_floating_1", 3, resource_name="192.168.1.1") Customer.fake_usage(customer, start, end, "net.allocated_ip", "ip_floating_2", 7) db.session.commit() second_tariff = self.create_tariff("Second Tariff", default=True) self.admin_client.customer.update(customer_id, tariff=second_tariff["tariff_id"]) customer = Customer.get_by_id(customer_id) customer.confirm_email() # clear db session customer = Customer.get_by_id(customer_id) customer.os_tenant_id = tenant_id # confirm email cleared tenant id Customer.fake_usage(customer, end + timedelta(minutes=1), end_second, self.service_nano_id, vm_nano, 1, resource_name="nano1") db.session.commit() report_tsv = self.get_customer_report(customer_id, start, end_report, "tsv", "detailed") report_csv = self.get_customer_report(customer_id, start, end_report, "csv", "detailed") report = self.get_customer_report(customer_id, start, end_report, "pdf", "detailed", filename="detailed.pdf") report_json = self.get_customer_report(customer_id, start, end_report, "json", "detailed") nano_cost = self.service_cost("2.23", start, end) nano2_cost = self.service_cost("2.23", start, middle_end) small_cost = self.service_cost("12.23", start, end) ip_floating_1_cost = self.service_cost("43.45", start, end)*3 ip_floating_2_cost = self.service_cost("43.45", start, end)*7 t1_cost = nano_cost + small_cost + nano2_cost + ip_floating_1_cost + ip_floating_2_cost self.assertEqual(len(report_json["tariffs"]), 2) self.assertEqual(Decimal(report_json["tariffs"][0]["total_cost"]), t1_cost) t2_cost = self.service_cost("2.23", end + timedelta(minutes=1), end_second) self.assertEqual(Decimal(report_json["tariffs"][1]["total_cost"]), t2_cost) self.assertEqual(Decimal(report_json["total"]["RUB"]), t1_cost + t2_cost) report = self.get_customer_report(customer_id, start, end_report, "pdf", filename="two_tariff.pdf") self.assertTrue(report) report = self.get_customer_report(customer_id, start, end_report, "csv", filename="two_tariff.csv") self.assertTrue(report) report = self.get_customer_report(customer_id, start, end_report, "tsv", filename="two_tariff.tsv") self.assertTrue(report) report_simple_json = self.get_customer_report(customer_id, start, end_report, "json", filename="two_tariff.pdf") self.assertTrue(report_simple_json) self.assertEqual(Decimal(report_simple_json["total"]["RUB"]), t1_cost + t2_cost) report = self.get_customer_report(customer_id, start, end_report, "pdf", "acceptance_act") report = self.get_customer_report(customer_id, end_report + timedelta(days=1), end_second + timedelta(days=31), "pdf", filename="empty.pdf")
def payment_pay(self, *args, **request_data): """Checks payment availability for customer. Parameters must be sent as json object. Request data looks like: { 'AccountId': '1000', # Customer ID here 'Amount': '10.00', 'AuthCode': 'A1B2C3', 'CardExpDate': '10/15', 'CardFirstSix': '424242', 'CardLastFour': '4242', 'CardType': 'Visa', 'Currency': 'RUB', 'Data': '{"myProp":"myProp value"}', 'DateTime': '2015-08-05 06:54:46', 'Description': 'Payment description', 'Email': '*****@*****.**', 'InvoiceId': '1234567', 'IpAddress': '46.251.83.16', 'IpCity': 'Moscow', 'IpCountry': 'RU', 'IpDistrict': 'Moscow federal district', 'IpLatitude': '56.329918', 'IpLongitude': '44.009193', 'IpRegion': 'Moscow district', 'Name': 'CARDHOLDER NAME', 'PaymentAmount': '10.00', # Not found in documentation but exist in request 'PaymentCurrency': 'RUB', # No in docs 'Status': 'Completed', 'TestMode': '1', 'Token': '477BBA133C182267FE5F086924ABDC5DB71F77BFC27F01F2843F2CDC69D89F05', 'TransactionId': '1211506' } :param Int TransactionId: Mandatory - System transaction number. :param Numeric Amount: Mandatory - Payment amount from widget. Dot as separator, two digits after dot. :param String Currency: Mandatory - Currency: RUB/USD/EUR/GBP from widget parameters. :param String InvoiceId: Not mandatory - Order number from widget parameters. :param String AccountId: Mandatory - Customer identifier from widget parameters. :param String SubscriptionId: Not mandatory - Subscription identifier from widget parameters (for recurrent payments). :param String Name: Not mandatory - Card holder name. :param String Email: Payer's e-mail :param DateTime: Mandatory - Payment creation date/time in UTC (yyyy-MM-dd HH:mm:ss). :param String IpAddress: Not mandatory - Payer IP-address :param String IpCountry: Not mandatory - Payer's country double-chars code (according to ISO3166-1) :param String IpCity: Not mandatory - Payer's city :param String IpRegion: Not mandatory - Payer's region. :param String IpDistrict: Not mandatory - Payer's district. :param String CardFirstSix: Mandatory - Credit card first 6 digits :param String CardLastFour: Mandatory - Credit card last 6 digits :param String CardType: Mandatory - Card payment system: Visa or MasterCard or Maestro :param String CardExpDate: Mandatory - Card expiration date MM/YY :param String Issuer: Not mandatory - Issuer bank name :param String IssuerBankCountry: Not mandatory - Issuer bank country double-char code (according to ISO3166-1) :param String Description: Not mandatory - Payment description from widget parameters. :param Json Data: Not mandatory - Any json-data from widget. :param Bit TestMode: Mandatory - Test mode flag (1 or 0) :param String Status: Mandatory - Payment status: Completed — for single-step, Authorized — for double-step. :param String Token: Not mandatory - Card token for recurrent payments without card data. :return: Status code, looks like {'code': 0} """ logbook.info("[payment_pay] Request info:{}", request_data) short_payment_info = dict([(key, request_data.get(key)) for key in PaymentsApi.payment_info_fields]) # Common validation validation_res, validation_info = self.validate_request(request_data, short_payment_info) if not validation_res: log_error("[payment_pay] {} Payment info: {}", validation_info, short_payment_info) # Expected successful code (no other codes were accepted for pay) return {"code": self.ERROR_OK} # Currency validation currency = request_data['Currency'] if not currency or currency not in conf.currency.active: log_error("[payment_pay] Invalid or incompatible currency: {}. Payment info: {}", currency, short_payment_info) # Expected successful code (no other codes were accepted for pay) return {"code": self.ERROR_OK} # Customer validation customer_id = request_data['AccountId'] customer = Customer.get_by_id(customer_id, False) if not customer: log_error("[payment_pay] Customer id '{}' not found. Payment info: {}", customer_id, short_payment_info) # Expected successful code (no other codes were accepted for pay) return {"code": self.ERROR_OK} if customer.is_test_mode(): # Payments in test mode is not allowed logbook.warning("[payment_pay] Customer {} in test mode. Payment info {}", customer, short_payment_info) return {'code': self.ERROR_OK} # Transaction validation transaction_id = request_data['TransactionId'] transaction_count = customer.check_account_history_transaction(transaction_id) if transaction_count: # This transaction already processed logbook.warning("[payment_pay] Customer {}. Transaction already processed. Payment info {}", customer, short_payment_info) return {'code': self.ERROR_OK} payment_description = _("Balance recharge via CloudPayments. Transaction: {}") # Process payment amount = Decimal(request_data['Amount']) customer.modify_balance(amount, currency, None, payment_description.format(request_data['TransactionId']), transaction_id=transaction_id) # Save customer's payment card for automated payments aux_data = request_data.get('Data') if aux_data and aux_data.get('saveAsDefault', False) is True: card_token = request_data.get("Token") if not card_token: log_error("[payment_pay] Customer {} wants to save card, but Token empty. Payment info: {}", customer, short_payment_info) else: card = CustomerCard.add_card(customer_id, request_data['CardLastFour'], request_data['CardType'], card_token, active=True) logbook.info("[payment_pay] Customer {}. Add payment card: {}", customer, card.display()) # Expected successful code (no other codes were accepted for pay) return {"code": 0}
def test_hour_stat(self, wrp_get_volumes, wrp_get_images, wrp_get_floating_ips, wrp_get_nova_servers, wrp_get_nova_flavors, wrp_get_snapshots, wrp_get_tenants, wrp_get_nova_limits, wrp_get_ceilometer_samples): self.create_tariff("stat") self.create_customer("*****@*****.**") blocked = self.create_customer("*****@*****.**") self.admin_client.customer.block(blocked["customer_id"]) entity = self.create_customer("*****@*****.**") self.admin_client.customer.update(entity["customer_id"], customer_type="entity") customer_info = self.create_customer("*****@*****.**", make_prod=True) tenant = ModelTenant.create("fake tenant_id", "fake tenant") customer = Customer.get_by_id(customer_info["customer_id"]) customer.os_tenant_id = tenant.tenant_id db.session.add(tenant) db.session.flush() deleted = self.create_customer("*****@*****.**", make_prod=True) self.admin_client.customer.delete(deleted["customer_id"]) from task.notifications import hour_stats from keystoneclient.v2_0.tenants import Tenant from novaclient.v2.flavors import Flavor from novaclient.v2.servers import Server from cinderclient.v2.volume_snapshots import Snapshot from cinderclient.v2.volumes import Volume from ceilometerclient.v2.samples import Sample info_flavors = [ {'OS-FLV-DISABLED:disabled': False, 'OS-FLV-EXT-DATA:ephemeral': 0, 'disk': 30, 'id': 'flavor_id_1', 'links': [{ 'href': 'http://openstack.org:8774/v2/2a870d56e2b9411a86fd1736f2217c10/flavors/0316748f-a62f-49ce-a5fe-22e84fb9ad62', 'rel': 'self'}, { 'href': 'http://openstack.org:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/0316748f-a62f-49ce-a5fe-22e84fb9ad62', 'rel': 'bookmark'}], 'name': 'Medium', 'os-flavor-access:is_public': False, 'ram': 8192, 'rxtx_factor': 1.0, 'swap': '', 'vcpus': 2}, {'OS-FLV-DISABLED:disabled': False, 'OS-FLV-EXT-DATA:ephemeral': 0, 'disk': 30, 'id': 'flavor_id_2', 'links': [{ 'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/flavors/25e56f22-0ead-41d3-8485-e07af3114de0', 'rel': 'self'}, { 'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/25e56f22-0ead-41d3-8485-e07af3114de0', 'rel': 'bookmark'}], 'name': 'M.Large', 'os-flavor-access:is_public': False, 'ram': 24576, 'rxtx_factor': 1.0, 'swap': '', 'vcpus': 4} ] info_servers = [ {'OS-DCF:diskConfig': 'AUTO', 'OS-EXT-AZ:availability_zone': 'zone', 'OS-EXT-SRV-ATTR:host': 'qk-9', 'OS-EXT-SRV-ATTR:hypervisor_hostname': 'qk-9.domain.tld', 'OS-EXT-SRV-ATTR:instance_name': 'instance-00000ef3', 'OS-EXT-STS:power_state': 1, 'OS-EXT-STS:task_state': None, 'OS-EXT-STS:vm_state': 'active', 'OS-SRV-USG:launched_at': '2015-10-01T20:23:32.000000', 'OS-SRV-USG:terminated_at': None, 'accessIPv4': '', 'accessIPv6': '', 'addresses': {'Internet-IPs': [{'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:e7:13:b3', 'OS-EXT-IPS:type': 'fixed', 'addr': '192.168.19.63', 'version': 4}]}, 'config_drive': '', 'created': '2015-10-01T20:23:15Z', 'flavor': { 'id': 'flavor_id_1', 'links': [{ 'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/6214ea5e-8d51-4025-885c-e14821b220cc', 'rel': 'bookmark'}]}, 'hostId': 'cb111a482618c143ca7a28c87ff0a93a1fb19283192509ac22c32af0', 'id': '4eda7eb2-e1c9-4f92-b32f-663c11d2deb0', 'image': '', 'key_name': None, 'links': [{ 'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/servers/4eda7eb2-e1c9-4f92-b32f-663c11d2deb0', 'rel': 'self'}, { 'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/servers/4eda7eb2-e1c9-4f92-b32f-663c11d2deb0', 'rel': 'bookmark'}], 'metadata': {}, 'name': 'active_test', 'os-extended-volumes:volumes_attached': [{'id': '115feaa7-1126-461d-ad60-067da6dff7c9'}], 'progress': 0, 'security_groups': [{'name': 'default'}], 'status': 'ACTIVE', 'tenant_id': 'tenant_id_1', 'updated': '2015-10-01T20:23:32Z', 'user_id': '25640457f00a485698caabf72bba5f8a'}, {'OS-DCF:diskConfig': 'AUTO', 'OS-EXT-AZ:availability_zone': 'zone', 'OS-EXT-SRV-ATTR:host': 'qk-13', 'OS-EXT-SRV-ATTR:hypervisor_hostname': 'qk-13.domain.tld', 'OS-EXT-SRV-ATTR:instance_name': 'instance-00000ef0', 'OS-EXT-STS:power_state': 1, 'OS-EXT-STS:task_state': None, 'OS-EXT-STS:vm_state': 'active', 'OS-SRV-USG:launched_at': '2015-10-01T20:21:17.000000', 'OS-SRV-USG:terminated_at': None, 'accessIPv4': '', 'accessIPv6': '', 'addresses': { 'Internet-IPs': [{'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:c6:e1:ac', 'OS-EXT-IPS:type': 'fixed', 'addr': '192.169.19.62', 'version': 4}]}, 'config_drive': '', 'created': '2015-10-01T20:21:01Z', 'flavor': {'id': 'flavor_id_2', 'links': [ { 'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/6214ea5e-8d51-4025-885c-e14821b220cc', 'rel': 'bookmark'} ]}, 'hostId': 'ccf318ebe253336d47f9bc105c723af000579aa2bc3111262e43e032', 'id': 'c7856a12-a749-47f2-8c7a-e4ee6e310ef6', 'image': '', 'key_name': 'testtesttest', 'links': [{ 'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/servers/c7856a12-a749-47f2-8c7a-e4ee6e310ef6', 'rel': 'self'}, { 'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/servers/c7856a12-a749-47f2-8c7a-e4ee6e310ef6', 'rel': 'bookmark'}], 'metadata': {}, 'name': 'testtesttest', 'os-extended-volumes:volumes_attached': [{'id': 'eac9cfdf-6f88-4ab9-b005-0e4f2534bc08'}], 'progress': 0, 'security_groups': [{'name': 'default'}], 'status': 'stopped', 'tenant_id': 'tenant_id_2', 'updated': '2015-10-01T20:21:18Z', 'user_id': '25640457f00a485698caabf72bba5f8a'} ] info_floating_ips = [ {'fixed_ip_address': None, 'floating_ip_address': '192.168.122.220', 'floating_network_id': '14d12e05-6e0f-4b1c-b8cd-43747eb5b8c5', 'id': '9a31e9ff-6b23-43e6-afad-ddd3ba194597', 'port_id': None, 'router_id': None, 'status': 'DOWN', 'tenant_id': 'd31e2dbfe716428daddbd4631bb73ab0'}, {'fixed_ip_address': None, 'floating_ip_address': '192.168.122.220', 'floating_network_id': '14d12e05-6e0f-4b1c-b8cd-43747eb5b8c5', 'id': '9a31e9ff-6b23-43e6-afad-ddd3ba194597', 'port_id': None, 'router_id': None, 'status': 'UP', 'tenant_id': 'd31e2dbfe716428daddbd4631bb73ab0'}] info_images = [ { 'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6', 'container_format': 'bare', 'created_at': '2015-08-05T10:24:00Z', 'disk_format': 'qcow2', 'file': '/v2/images/cf70343a-54a7-46e8-9707-330f149d16ef/file', 'id': 'cf70343a-54a7-46e8-9707-330f149d16ef', 'min_disk': 0, 'min_ram': 0, 'name': 'cirros-0.3.4-x86_64', 'owner': '514c60f95d9240508be98d1bf20fdccb', 'protected': False, 'schema': '/v2/schemas/image', 'size': 5, 'status': 'active', 'tags': [], 'updated_at': '2015-08-05T10:24:00Z', 'virtual_size': None, 'visibility': 'public' }, { 'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6', 'container_format': 'bare', 'created_at': '2015-08-05T10:24:00Z', 'disk_format': 'qcow2', 'file': '/v2/images/cf70343a-54a7-46e8-9707-330f149d16ef/file', 'id': 'cf70343a-54a7-46e8-9707-330f149d16ef', 'min_disk': 0, 'min_ram': 0, 'name': 'cirros-0.3.4-x86_64', 'owner': '514c60f95d9240508be98d1bf20fdccb', 'protected': False, 'schema': '/v2/schemas/image', 'size': 7, 'status': 'active', 'tags': [], 'updated_at': '2015-08-05T10:24:00Z', 'virtual_size': None, 'visibility': 'private' }] info_volumes = [ { 'attachments': [], 'availability_zone': 'nova', 'bootable': 'false', 'consistencygroup_id': None, 'created_at': '2015-10-08T15:24:22.000000', 'description': None, 'encrypted': False, 'id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc', 'links': [ { 'href': 'http://192.168.3.101:8776/v2/514c60f95d9240508be98d1bf20fdccb/volumes/a5514296-4c70-426c-ba74-3e1ffc29bffc', 'rel': 'self'}, { 'href': 'http://192.168.3.101:8776/514c60f95d9240508be98d1bf20fdccb/volumes/a5514296-4c70-426c-ba74-3e1ffc29bffc', 'rel': 'bookmark'}], 'metadata': {}, 'multiattach': False, 'name': 'denis_test_volume_1', 'os-vol-host-attr:host': 'ubuntu-kilo#GlusterFS', 'os-vol-mig-status-attr:migstat': None, 'os-vol-mig-status-attr:name_id': None, 'os-vol-tenant-attr:tenant_id': 'aee181ad99394b9e81ecad5d61d09261', 'os-volume-replication:driver_data': None, 'os-volume-replication:extended_status': None, 'replication_status': 'disabled', 'size': 7, 'snapshot_id': None, 'source_volid': None, 'status': 'available', 'user_id': '5f796d5bee7f424180c6ba79f55811fe', 'volume_type': None }, {'attachments': [{'attachment_id': '6464d0e4-7bfa-4284-87bd-85d151e4fdfd', 'device': '/dev/vda', 'host_name': None, 'id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c', 'server_id': 'a96aa81d-c5e9-4b05-8e6d-9db7838cf94d', 'volume_id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c'}], 'availability_zone': 'nova', 'bootable': 'true', 'consistencygroup_id': None, 'created_at': '2015-10-08T14:14:19.000000', 'description': 'hdisk1 hdisk1 hdisk1', 'encrypted': False, 'id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c', 'links': [{ 'href': 'http://192.168.3.101:8776/v2/514c60f95d9240508be98d1bf20fdccb/volumes/51e36e6b-aa99-4adc-8f50-e6066a8c885c', 'rel': 'self'}, { 'href': 'http://192.168.3.101:8776/514c60f95d9240508be98d1bf20fdccb/volumes/51e36e6b-aa99-4adc-8f50-e6066a8c885c', 'rel': 'bookmark'}], 'metadata': {'attached_mode': 'rw', 'readonly': 'False'}, 'multiattach': False, 'name': 'hdisk1', 'os-vol-host-attr:host': 'ubuntu-kilo#GlusterFS', 'os-vol-mig-status-attr:migstat': None, 'os-vol-mig-status-attr:name_id': None, 'os-vol-tenant-attr:tenant_id': '8e165ea202e346299280cb7afd9ef828', 'os-volume-replication:driver_data': None, 'os-volume-replication:extended_status': None, 'replication_status': 'disabled', 'size': 9, 'snapshot_id': None, 'source_volid': None, 'status': 'in-use', 'user_id': '392b8565a7ad497793d6bd826db6dbc9', 'volume_image_metadata': {'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6', 'container_format': 'bare', 'disk_format': 'qcow2', 'image_id': 'cf70343a-54a7-46e8-9707-330f149d16ef', 'image_name': 'cirros-0.3.4-x86_64', 'min_disk': '0', 'min_ram': '0', 'size': '13287936'}, } ] info_snapshots = [ { 'created_at': '2015-10-08T15:25:00.000000', 'description': '', 'id': '055f5dc8-2224-47eb-8a55-9c3ecf2f74a0', 'metadata': {}, 'name': 'test_snapshot_1', 'os-extended-snapshot-attributes:progress': '100%', 'os-extended-snapshot-attributes:project_id': 'aee181ad99394b9e81ecad5d61d09261', 'size': 3, 'status': 'available', 'volume_id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc' }, { 'created_at': '2015-10-08T15:25:00.000000', 'description': '', 'id': '055f5dc8-2224-47eb-8a55-9c3ecf2f74a0', 'metadata': {}, 'name': 'test_snapshot_2', 'os-extended-snapshot-attributes:progress': '100%', 'os-extended-snapshot-attributes:project_id': 'aee181ad99394b9e81ecad5d61d09261', 'size': 5, 'status': 'available', 'volume_id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc' } ] info_tenants = [ {'description': 'Unit test tenant - 1', 'enabled': True, 'id': 'tenant_id_1', 'name': 'tenant_name_1'}, {'description': 'Unit test tenant - 2', 'enabled': True, 'id': 'tenant_id_2', 'name': 'tenant_name_2'}, {'description': 'Unit test tenant - 3', 'enabled': True, 'id': 'tenant_id_3', 'name': 'tenant_name_3'}, ] info_nova_limits = { 'maxImageMeta': 128, 'maxPersonality': 5, 'maxPersonalitySize': 10240, 'maxSecurityGroupRules': 20, 'maxSecurityGroups': 10, 'maxServerGroupMembers': 10, 'maxServerGroups': 10, 'maxServerMeta': 128, 'maxTotalCores': 20, 'maxTotalFloatingIps': 10, 'maxTotalInstances': 20, 'maxTotalKeypairs': 10, 'maxTotalRAMSize': 20480, 'totalCoresUsed': 1, 'totalFloatingIpsUsed': 0, 'totalInstancesUsed': 1, 'totalRAMUsed': 8192, 'totalSecurityGroupsUsed': 1, 'totalServerGroupsUsed': 0 } info_bandwidth = [ {'id': 'c9510474-5e04-11e5-920d-fa163e4b35b4', 'metadata': {'fref': 'None', 'instance_id': '1b02a1c2-7a6e-404a-b355-d2840d295677', 'instance_type': 'ef9a407d-742d-4f23-9055-decbccb143d9', 'mac': 'fa:16:3e:9e:18:12', 'name': 'tap345a6b63-eb'}, 'meter': 'network.incoming.bytes', 'project_id': '03926f96177e4df9a0fc5c77f6e674d8', 'recorded_at': '2015-09-18T12:57:15.769000', 'resource_id': 'instance-00000018-1b02a1c2-7a6e-404a-b355-d2840d295677-tap345a6b63-eb', 'source': 'openstack', 'timestamp': '2015-09-18T12:57:15', 'type': 'cumulative', 'unit': 'B', 'user_id': 'c1ef3d08d9694acb8740ccb66d0ba945', 'volume': 11.0 }, ] wrp_get_ceilometer_samples.return_value = [Sample(None, s) for s in info_bandwidth] wrp_get_images.return_value = info_images wrp_get_floating_ips.return_value = info_floating_ips wrp_get_tenants.return_value = [Tenant(None, t) for t in info_tenants] wrp_get_nova_servers.return_value = [Server(None, s) for s in info_servers] wrp_get_nova_flavors.return_value = [Flavor(None, f) for f in info_flavors] wrp_get_volumes.return_value = [Volume(None, volume) for volume in info_volumes] wrp_get_snapshots.return_value = [Snapshot(None, snapshot) for snapshot in info_snapshots] wrp_get_nova_limits.return_value = info_nova_limits # Run stat collection hour_stats() expected_stats = { "stats.flavor.total": 2, "stats.flavor.Medium": 1, 'stats.ip.floating.active_customer': 6, 'stats.ip.floating.blocked_customer': 2, 'stats.ip.floating.customer_mode-production': 2, 'stats.ip.floating.customer_mode-test': 6, 'stats.ip.floating.customer_type-entity': 2, 'stats.ip.floating.customer_type-private': 6, 'stats.ip.floating.ip_status-DOWN': 4, 'stats.ip.floating.ip_status-UP': 4, 'stats.ip.floating.total': 8, 'stats.storage.image.total': 2, 'stats.storage.image.total_size': 12, 'stats.storage.image.visibility-public': 1, 'stats.storage.image.visibility-private': 1, 'stats.storage.image.status-active': 2, 'stats.storage.volume.total': 2, 'stats.storage.volume.total_size': 16, 'stats.storage.volume.volume-bootable': 2, 'stats.storage.volume.status-available': 1, 'stats.storage.volume.status-in-use': 1, 'stats.storage.snapshots.total': 2, 'stats.storage.snapshots.total_size': 8, 'stats.storage.snapshots.available': 2, 'stats.resources.totalRAMUsed': 8192*1, 'stats.resources.totalCoresUsed': 1, 'stats.resources.flavor.Medium.ram': 8192, 'stats.resources.flavor.Medium.vcpus': 2, 'stats.network.outgoing.bytes': info_bandwidth[0]['volume'] * len(info_tenants), 'stats.network.incoming.bytes': info_bandwidth[0]['volume'] * len(info_tenants), } for k, v in expected_stats.items(): self.verify_metric(k, v)
def customer_auto_report(customer_id, time_now): from model import Customer, ScheduledTask from task.mail import send_email customer = Customer.get_by_id(customer_id) if not customer: logbook.error("Can't find customer {} for report generation", customer_id) return report_task = ScheduledTask.get_by_customer(customer_id, Customer.AUTO_REPORT_TASK) if not report_task: logbook.error("Can't find auto report task for customer {}", customer_id) return logbook.debug("Start auto-report task for customer {}: {}", customer, report_task) report_task.start() previous_next_send = report_task.next_scheduled.replace(tzinfo=utc) if previous_next_send is None or previous_next_send > time_now: logbook.warning("Looks like report for customer {} already sent. Next send: {}, current time {}", customer, previous_next_send, time_now) report_task.completed(now=time_now) return report_begin = day_start(report_task.last or time_now) _, report_end = report_task.task_range(time_now, previous_interval=True) report_end = day_start(report_end) report_id = CustomerReportId(customer.customer_id, report_begin, report_end, conf.customer.report.type, conf.customer.report.format, customer.locale) report_file_generate(report_id) # report_file_generate closed session so we should initialize customer again customer = Customer.get_by_id(customer_id) report_task = ScheduledTask.get_by_customer(customer_id, Customer.AUTO_REPORT_TASK) report_cache = ReportCache() report = report_cache.get_report_aggregated(report_id) if not report or not report["tariffs"]: logbook.info("Report is empty for customer {}", customer) report_task.completed(now=time_now) return report_file = report_cache.get_report(report_id) if not report_file: logbook.error("Report generation failed") report_task.completed(False) return filename = Report.generate_file_name(customer.get_name(), report_begin, report_end, conf.customer.report.format) subject, body = MessageTemplate.get_rendered_message( MessageTemplate.CUSTOMER_AUTO_REPORT, customer.locale_language(), customer_name=customer.get_name(), currency=customer.tariff.currency, report_start=report_begin, report_end=report_end) subscription_info = customer.subscription_info()['billing'] if subscription_info["enable"]: send_email.delay(subscription_info["email"], subject, body, attachments=[(filename, report_file)]) report_task.completed(now=time_now) comment_fmt = "%s - %s" % (report_begin.strftime('%Y-%m-%d'), report_end.strftime('%Y-%m-%d')) for currency, amount in report["total"].items(): amount = Decimal(amount) customer.modify_balance(-amount, currency, None, comment_fmt) account = customer.get_account(currency) account.charge(-amount) db.session.commit()
def test_collector(self): start_time = datetime.datetime(2015, 3, 20, 9, 12) end_time = datetime.datetime(2015, 5, 1) project = Tenant("boss", start_time) disk = Disk(project, "test_disk", start_time, 1234567890) disk2 = Disk(project, "test_disk2", start_time, 3456) volume = Volume(project, "figvam", datetime.datetime.now(), 2) vm = Instance(project, "teamcity", "Nano") vm2 = Instance(project, "teamcity1", "TestFlavor") disk.repeat_message(start_time, end_time) disk2.repeat_message(start_time, end_time) vm.repeat_message(start_time, end_time) vm2.repeat_message(start_time, end_time) volume.repeat_message(start_time, end_time) hour_price = Decimal(self.volume_size_price) * 2 + Decimal(self.image_size_price) * 3 + \ + Decimal(self.nano_price) with mock.patch("os_interfaces.openstack_wrapper.openstack") as openstack: openstack.get_tenant_usage = project.usage project.prepare_messages() tenants_usage = self.collector.run_usage_collection(end_time + datetime.timedelta(hours=10)) tenant_usage = next(iter(tenants_usage.values())) self.assertTrue(tenant_usage) self.assertEqual(self.collector.errors, 0) for time_label, time_label_usage in tenant_usage.items(): withdraw = time_label_usage[1] self.assertLess(withdraw - hour_price, 1e-6) for usage in time_label_usage[0]: if usage["service_id"] == "image.size": self.assertEqual(usage.volume, 1234567890) if usage['service_id'] == "volume.size": self.assertEqual(usage.volume, 2 * 1073741824) # 2GB self.assertEqual(outbox[1].subject, '%s: Notice on service adding notification' % conf.provider.cloud_name) account = Customer.get_by_id(project.customer_id).account_dict()["RUB"] self.assertEqual(account["balance"], Decimal(project.start_balance)) hours = int((end_time - start_time).total_seconds() // 3600) + 1 total_cost = hours * hour_price self.assertLess(abs(account["withdraw"] - total_cost), 0.0001) report = self.get_report(project.customer_id, start_time, end_time, "json") self.assertEqual(report["total"]["RUB"], decimal_to_string(total_cost)) report = self.get_report(project.customer_id, start_time, end_time, "json", report_is_ready=True) report_ru = self.get_report(project.customer_id, start_time, end_time, "csv") customer = Customer.get_by_id(project.customer_id) customer.locale = "en_us" db.session.commit() report_en = self.get_report(project.customer_id, start_time, end_time, "csv", filename="report_en.csv") self.assertNotEqual(report_ru, report_en) self.assertGreater(report_ru.count(b";"), 0) self.assertEqual(report_en.count(b";"), 0) # pdf en self.get_report(project.customer_id, start_time, end_time, "pdf") customer = Customer.get_by_id(project.customer_id) customer.locale = "ru_ru" db.session.commit() # pdf ru self.get_report(project.customer_id, start_time, end_time, "pdf") # json after pdf json_report = self.get_report(project.customer_id, start_time, end_time, "json", report_is_ready=True) self.cabinet_client.auth(project.customer_email, project.customer_password) customer_report = self.get_report_me(start_time, end_time, "json", report_is_ready=True) self.assertEqual(json_report, customer_report) self.get_report_me(start_time - datetime.timedelta(days=30), start_time, "csv", filename="empty.csv") self.get_report_me(start_time - datetime.timedelta(days=30), start_time, "pdf", filename="empty.pdf")