|
|
# -*- coding: utf-8 -*-
|
|
|
import sys
|
|
|
import collections
|
|
|
import datetime
|
|
|
import calendar
|
|
|
import os
|
|
|
from collections import defaultdict
|
|
|
|
|
|
import numpy as np
|
|
|
import pandas as pd
|
|
|
from openpyxl import Workbook
|
|
|
from openpyxl.styles import NamedStyle, PatternFill, Font, Alignment, Border, Side, colors
|
|
|
import boto3
|
|
|
import time
|
|
|
import os
|
|
|
from collections import defaultdict
|
|
|
import openpyxl
|
|
|
import time
|
|
|
import datetime
|
|
|
import calendar
|
|
|
from calendar import monthrange
|
|
|
from docxtpl import DocxTemplate
|
|
|
from pandas import Index
|
|
|
import shutil
|
|
|
|
|
|
_dict = {
|
|
|
# 6910账号aksk
|
|
|
'AWS_ACCESS_KEY_ID': 'AKIA4FU4JFDXO5J2ISNY',
|
|
|
'AWS_SECRET_ACCESS_KEY': 'AVfPZ/XryDsoWmYB293eNPOyiO82x9xR62KFKezS',
|
|
|
# 7422账号aksk
|
|
|
'GLOBAL_AWS_ACCESS_KEY_ID': "AKIAQWIJ3GB7CTO5GAWY",
|
|
|
'GLOBAL_AWS_SECRET_ACCESS_KEY': "o1iQFQFSW+W/GGzjIRcNu1RDO1s72Uv2pJK/zf3z"
|
|
|
}
|
|
|
aws_aksk = {
|
|
|
"089027636324": {
|
|
|
"account_type": "amazon-china",
|
|
|
"aws_access_key_id": "",
|
|
|
"aws_secret_access_key": "",
|
|
|
"bucket": "089027636324billing",
|
|
|
"credential_type": "Amazon IAM Role",
|
|
|
"role_arn": "arn:aws-cn:iam::089027636324:role/089027636324billing",
|
|
|
"external_id": "l2c-1i5u1ds0",
|
|
|
},
|
|
|
}
|
|
|
def auto_download_file_form_s3(file: tuple):
|
|
|
for i in file:
|
|
|
payer_id = i.split('-')[0]
|
|
|
credential = get_credentials(payer_id)
|
|
|
bucket = credential.pop('bucket')
|
|
|
s3_client = boto3.client('s3', **credential)
|
|
|
print('{}开始下载'.format(i))
|
|
|
s3_client.download_file(
|
|
|
bucket,i, i)
|
|
|
#shutil.copy(i, data_dir+i)
|
|
|
#shutil.move(i, os.path.join(data_dir, i))
|
|
|
|
|
|
print('{}下载完成'.format(i))
|
|
|
def get_credentials(payer_id):
|
|
|
credential = aws_aksk.get(payer_id, None)
|
|
|
if not credential:
|
|
|
return
|
|
|
if credential.get('account_type', None) == 'amazon-china':
|
|
|
region_name = 'cn-northwest-1'
|
|
|
aws_access_key_id = _dict['AWS_ACCESS_KEY_ID']
|
|
|
aws_secret_access_key = _dict['AWS_SECRET_ACCESS_KEY']
|
|
|
else:
|
|
|
region_name = 'us-east-2'
|
|
|
aws_access_key_id = _dict['GLOBAL_AWS_ACCESS_KEY_ID']
|
|
|
aws_secret_access_key = _dict['GLOBAL_AWS_SECRET_ACCESS_KEY']
|
|
|
if credential.get('credential_type', None) == 'Amazon Access Key':
|
|
|
return {
|
|
|
'aws_access_key_id': credential['aws_access_key_id'],
|
|
|
'aws_secret_access_key': credential['aws_secret_access_key'],
|
|
|
'region_name': region_name,
|
|
|
'bucket': credential['bucket']
|
|
|
}
|
|
|
else:
|
|
|
sts = boto3.client('sts',
|
|
|
region_name=region_name,
|
|
|
aws_access_key_id=aws_access_key_id,
|
|
|
aws_secret_access_key=aws_secret_access_key
|
|
|
)
|
|
|
sts_credential = sts.assume_role(
|
|
|
RoleArn=credential['role_arn'],
|
|
|
RoleSessionName='crawl-billing' + str(time.time()),
|
|
|
DurationSeconds=900,
|
|
|
ExternalId=credential['external_id']
|
|
|
)
|
|
|
return {
|
|
|
'aws_access_key_id': sts_credential['Credentials']['AccessKeyId'],
|
|
|
'aws_secret_access_key': sts_credential['Credentials']['SecretAccessKey'],
|
|
|
'region_name': region_name,
|
|
|
'aws_session_token': sts_credential['Credentials']['SessionToken'],
|
|
|
'bucket': credential['bucket']
|
|
|
}
|
|
|
|
|
|
word_dir = 'D:\workspace\zhangdanjiaoben\other/三星/word/'
|
|
|
info_dir = 'D:\workspace\zhangdanjiaoben\other/三星/info/'
|
|
|
pivot_data_dir = 'D:\workspace\zhangdanjiaoben\other/三星/pivot/'
|
|
|
|
|
|
csv_columns2 = Index(
|
|
|
[
|
|
|
'InvoiceID',
|
|
|
'PayerAccountId',
|
|
|
'LinkedAccountId',
|
|
|
'RecordType',
|
|
|
'RecordID',
|
|
|
'BillingPeriodStartDate',
|
|
|
'BillingPeriodEndDate',
|
|
|
'InvoiceDate',
|
|
|
'PayerAccountName',
|
|
|
'LinkedAccountName',
|
|
|
'TaxationAddress',
|
|
|
'PayerPONumber',
|
|
|
'ProductCode',
|
|
|
'ProductName',
|
|
|
'SellerOfRecord',
|
|
|
'UsageType',
|
|
|
'Operation',
|
|
|
'AvailabilityZone',
|
|
|
'RateId',
|
|
|
'ItemDescription',
|
|
|
'UsageStartDate',
|
|
|
'UsageEndDate',
|
|
|
'UsageQuantity',
|
|
|
'BlendedRate',
|
|
|
'CurrencyCode',
|
|
|
'CostBeforeTax',
|
|
|
'Credits',
|
|
|
'TaxAmount',
|
|
|
'TaxType',
|
|
|
'TotalCost',
|
|
|
'aws:autoscaling:groupName',
|
|
|
'aws:cloudformation:logical-id',
|
|
|
'aws:cloudformation:stack-id',
|
|
|
'aws:cloudformation:stack-name',
|
|
|
'aws:createdBy',
|
|
|
'aws:ec2launchtemplate:id',
|
|
|
'aws:ec2launchtemplate:version',
|
|
|
'aws:elasticmapreduce:instance-group-role',
|
|
|
'aws:elasticmapreduce:job-flow-id',
|
|
|
'user:APP-ID',
|
|
|
'user:AccountID',
|
|
|
'user:Author',
|
|
|
'user:COST TAG 1',
|
|
|
'user:Cost Center',
|
|
|
'user:DLP',
|
|
|
'user:Description',
|
|
|
'user:Environment',
|
|
|
'user:EnvironmentType',
|
|
|
'user:KubernetesCluster',
|
|
|
'user:ManagedByAmazonSageMakerResource',
|
|
|
'user:NAME',
|
|
|
'user:Name',
|
|
|
'user:Patch Group',
|
|
|
'user:Product ID',
|
|
|
'user:ProjectName',
|
|
|
'user:Responsible',
|
|
|
'user:Role',
|
|
|
'user:Scope',
|
|
|
'user:Stage',
|
|
|
'user:Terraform',
|
|
|
'user:Tool',
|
|
|
'user:createdBy',
|
|
|
'user:data-source',
|
|
|
'user:data-source-billing',
|
|
|
'user:desc',
|
|
|
'user:description',
|
|
|
'user:elasticbeanstalk:environment-id',
|
|
|
'user:elasticbeanstalk:environment-name',
|
|
|
'user:environment',
|
|
|
'user:hub',
|
|
|
'user:k8s.io/cluster-autoscaler/node-template/label/kops.k8s.io/instancegroup',
|
|
|
'user:k8s.io/etcd/events',
|
|
|
'user:k8s.io/etcd/main',
|
|
|
'user:k8s.io/role/master',
|
|
|
'user:k8s.io/role/node',
|
|
|
'user:kubernetes.io/cluster/infotain-e2e.k8s.local',
|
|
|
'user:kubernetes.io/cluster/infotain-prod.k8s.local',
|
|
|
'user:kubernetes.io/created-for/pv/name',
|
|
|
'user:kubernetes.io/created-for/pvc/name',
|
|
|
'user:kubernetes.io/created-for/pvc/namespace',
|
|
|
'user:kubernetes.io/service-name',
|
|
|
'user:name',
|
|
|
'user:namespace',
|
|
|
'user:owner',
|
|
|
'user:project',
|
|
|
'user:resourcePrefix',
|
|
|
'user:role',
|
|
|
'user:server-name',
|
|
|
'user:snsTopicArn',
|
|
|
'user:stage',
|
|
|
'user:sub-product',
|
|
|
'user:workload-type'])
|
|
|
|
|
|
data_type = {
|
|
|
'UsageStartDate': object,
|
|
|
'UsageEndDate': object,
|
|
|
'InvoiceID': object,
|
|
|
'ProductName': object,
|
|
|
'PayerAccountId': object,
|
|
|
'LinkedAccountId': object,
|
|
|
'UnBlendedCost': str,
|
|
|
'BlendedCost': str,
|
|
|
'ItemDescription': object,
|
|
|
'RecordType': object
|
|
|
}
|
|
|
|
|
|
|
|
|
def new_round(_float, _len=2) -> float:
|
|
|
"""
|
|
|
Parameters
|
|
|
----------
|
|
|
_float:
|
|
|
_len: int, 指定四舍五入需要保留的小数点后几位数为_len
|
|
|
|
|
|
Returns
|
|
|
-------
|
|
|
type ==> float, 返回四舍五入后的值
|
|
|
"""
|
|
|
try:
|
|
|
if isinstance(_float, float):
|
|
|
if 'e' in str(_float).lower():
|
|
|
return round(_float, _len)
|
|
|
elif str(_float)[::-1].find('.') <= _len:
|
|
|
return _float
|
|
|
elif str(_float)[-1] == '5':
|
|
|
return round(float(str(_float)[:-1] + '6'), _len)
|
|
|
else:
|
|
|
return round(_float, _len)
|
|
|
elif isinstance(_float, str):
|
|
|
_float = _float.replace(',', '')
|
|
|
return new_round(float(_float), _len)
|
|
|
else:
|
|
|
return round(_float, _len)
|
|
|
except Exception as e:
|
|
|
print(_float, _len, e)
|
|
|
|
|
|
class GenerateWord(object):
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
self.args = args
|
|
|
self.kwargs = kwargs
|
|
|
|
|
|
def my_sum(self, data_dict, loc, length=2):
|
|
|
# 模板内使用
|
|
|
count = 0.0
|
|
|
for item in data_dict.values():
|
|
|
x = self.reverse_fill(item[loc])
|
|
|
count += x
|
|
|
a = new_round(count, length)
|
|
|
return a
|
|
|
|
|
|
@staticmethod
|
|
|
def reverse_fill(value_str: float, length=6):
|
|
|
return new_round(value_str, length)
|
|
|
|
|
|
@staticmethod
|
|
|
def get_bank(**kwargs):
|
|
|
info_map = {
|
|
|
'ch bj': os.path.join(info_dir, 'cn_bank_bj.txt'),
|
|
|
'ch hk': os.path.join(info_dir, 'cn_bank_hk.txt'),
|
|
|
'en bj': os.path.join(info_dir, 'en_bank_bj.txt'),
|
|
|
'en hk': os.path.join(info_dir, 'en_bank_hk.txt')
|
|
|
}
|
|
|
return info_map.get(kwargs.get('bank')) or info_map['ch bj']
|
|
|
|
|
|
@staticmethod
|
|
|
def get_region_display(data: dict):
|
|
|
for i in data.keys():
|
|
|
if i == 'cn-north-1':
|
|
|
data['北京区资源费'] = data.pop(i)
|
|
|
elif i == 'cn-northwest-1':
|
|
|
data['宁夏区资源费'] = data.pop(i)
|
|
|
return data
|
|
|
|
|
|
@staticmethod
|
|
|
def get_date_array(_date: str):
|
|
|
_array = monthrange(int(_date[:4]), int(_date[5:7]))
|
|
|
return [
|
|
|
"%s-%s-01" % (_date[:4], _date[5:7]),
|
|
|
"%s-%s-%2d" % (_date[:4], _date[5:7], _array[1]),
|
|
|
]
|
|
|
|
|
|
@staticmethod
|
|
|
def fill(value, length=2):
|
|
|
temp = "{:,.%sf}" % length
|
|
|
if isinstance(value, str):
|
|
|
value = value.replace(',', '')
|
|
|
return temp.format(float(value))
|
|
|
elif isinstance(value, int) or isinstance(value, float):
|
|
|
return temp.format(value)
|
|
|
else:
|
|
|
return temp.format(0)
|
|
|
|
|
|
@staticmethod
|
|
|
def display_time(day_str, str_fmt="%Y-%m-%d %H:%M:%S"):
|
|
|
# 设置中文编码格式
|
|
|
# import locale
|
|
|
# locale.setlocale(locale.LC_CTYPE, 'chinese')
|
|
|
zh_fmt = '%Y年%m月%d日'
|
|
|
# en_fmt = '%B %d, %Y'
|
|
|
return time.strftime(zh_fmt, time.strptime(str(day_str), str_fmt))
|
|
|
|
|
|
def get_currency(self):
|
|
|
if self.kwargs.get("currency") == 'USD':
|
|
|
return "$"
|
|
|
return "¥"
|
|
|
|
|
|
def get_temple_number(self, number):
|
|
|
data = [
|
|
|
self.fill(number * 1.06),
|
|
|
self.fill(number),
|
|
|
self.fill(0),
|
|
|
self.fill(number * 0.06),
|
|
|
]
|
|
|
return data
|
|
|
|
|
|
@staticmethod
|
|
|
def check_path_creat(path):
|
|
|
if not os.path.exists(path):
|
|
|
os.mkdir(path)
|
|
|
|
|
|
class SamsungGenerateWord(GenerateWord):
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
super().__init__(*args, **kwargs)
|
|
|
self.link_dict = kwargs.get('link_dict', None)
|
|
|
self.filename = kwargs.get('filename', None)
|
|
|
|
|
|
def create_word(self):
|
|
|
payerid = self.filename.split('-')[0]
|
|
|
link_data = []
|
|
|
filedate, noticedate, due_data = from_filename_get_datetime(self.filename)
|
|
|
amount = 0
|
|
|
noticenumber = ''
|
|
|
link_list = []
|
|
|
for key, value in self.link_dict.items():
|
|
|
if key == payerid:
|
|
|
continue
|
|
|
noticenumber = value.pop('InvoiceID')
|
|
|
totalcost = value.pop('TotalCost')
|
|
|
amount += totalcost
|
|
|
product_code_dict = defaultdict()
|
|
|
for k, v in value.items():
|
|
|
product_code_dict[k] = self.get_temple_number(v)
|
|
|
totalcost_li = self.get_temple_number(totalcost)
|
|
|
link_data.append(
|
|
|
{
|
|
|
'linkedid': key,
|
|
|
'totalcost': totalcost_li,
|
|
|
'product_code_dict': product_code_dict,
|
|
|
},
|
|
|
)
|
|
|
if key.isdigit():
|
|
|
link_list.append(key)
|
|
|
date = self.get_date_array(filedate)
|
|
|
for i in range(len(date)):
|
|
|
date[i] = self.display_time(date[i], str_fmt="%Y-%m-%d")
|
|
|
bank_info_list = []
|
|
|
with open(self.get_bank(), 'r', encoding='utf8') as f:
|
|
|
for line in f.readlines():
|
|
|
if "{{company_email}}" in line:
|
|
|
line = line.replace(
|
|
|
'{{company_email}}', self.kwargs.get(
|
|
|
'company_email', ''))
|
|
|
bank_info_list.append(line.strip('\n'))
|
|
|
xx = self.get_template()
|
|
|
template = DocxTemplate(xx)
|
|
|
content = {
|
|
|
'storage': '三星',
|
|
|
'link_list': link_list,
|
|
|
'noticenumber': noticenumber,
|
|
|
'noticedate': noticedate,
|
|
|
'currency': self.get_currency(),
|
|
|
'region_display': '',
|
|
|
# 'totalcost': totalcost_li,
|
|
|
# 'product_code_dict': product_code_dict,
|
|
|
'date': date,
|
|
|
'workday': due_data,
|
|
|
'bank_info_list': bank_info_list,
|
|
|
'link_data': link_data,
|
|
|
'amount': self.get_temple_number(amount),
|
|
|
}
|
|
|
file_name = '{}_AWS账单{}.docx'.format(payerid, filedate)
|
|
|
doc_file_path = os.path.join(word_dir, self.filename)
|
|
|
self.check_path_creat(doc_file_path)
|
|
|
doc_file_name = os.path.join(doc_file_path, file_name)
|
|
|
template.render(context=content)
|
|
|
template.save(doc_file_name)
|
|
|
print('{}_亚马逊云科技账单{}.docx 生成完成'.format(payerid, filedate))
|
|
|
return [doc_file_name]
|
|
|
|
|
|
@staticmethod
|
|
|
def get_template():
|
|
|
return os.path.join(info_dir, 'china-template-3.docx')
|
|
|
|
|
|
def from_filename_get_datetime(filename: str):
|
|
|
dt = filename[-7:]
|
|
|
date = datetime.datetime.strptime(dt, "%Y-%m")
|
|
|
days = calendar.monthrange(date.year, date.month)
|
|
|
later1dt = date + datetime.timedelta(days[1] + 1)
|
|
|
later1 = later1dt.strftime("%Y-%m-%d")
|
|
|
n_days = calendar.monthrange(later1dt.year, later1dt.month)
|
|
|
later2dt = later1dt + datetime.timedelta(n_days[1])
|
|
|
later2 = later2dt.strftime("%Y-%m-%d")
|
|
|
return dt, later1, later2
|
|
|
|
|
|
|
|
|
class GenerateWord(object):
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
self.args = args
|
|
|
self.kwargs = kwargs
|
|
|
|
|
|
def my_sum(self, data_dict, loc, length=2):
|
|
|
# 模板内使用
|
|
|
count = 0.0
|
|
|
for item in data_dict.values():
|
|
|
x = self.reverse_fill(item[loc])
|
|
|
count += x
|
|
|
a = new_round(count, length)
|
|
|
return a
|
|
|
|
|
|
@staticmethod
|
|
|
def reverse_fill(value_str: float, length=6):
|
|
|
return new_round(value_str, length)
|
|
|
|
|
|
@staticmethod
|
|
|
def get_bank(**kwargs):
|
|
|
info_map = {
|
|
|
'ch bj': os.path.join(info_dir, 'cn_bank_bj.txt'),
|
|
|
'ch hk': os.path.join(info_dir, 'cn_bank_hk.txt'),
|
|
|
'en bj': os.path.join(info_dir, 'en_bank_bj.txt'),
|
|
|
'en hk': os.path.join(info_dir, 'en_bank_hk.txt')
|
|
|
}
|
|
|
return info_map.get(kwargs.get('bank')) or info_map['ch bj']
|
|
|
|
|
|
@staticmethod
|
|
|
def get_region_display(data: dict):
|
|
|
for i in data.keys():
|
|
|
if i == 'cn-north-1':
|
|
|
data['北京区资源费'] = data.pop(i)
|
|
|
elif i == 'cn-northwest-1':
|
|
|
data['宁夏区资源费'] = data.pop(i)
|
|
|
return data
|
|
|
|
|
|
@staticmethod
|
|
|
def get_date_array(_date: str):
|
|
|
_array = monthrange(int(_date[:4]), int(_date[5:7]))
|
|
|
return [
|
|
|
"%s-%s-01" % (_date[:4], _date[5:7]),
|
|
|
"%s-%s-%2d" % (_date[:4], _date[5:7], _array[1]),
|
|
|
]
|
|
|
|
|
|
@staticmethod
|
|
|
def fill(value, length=2):
|
|
|
temp = "{:,.%sf}" % length
|
|
|
if isinstance(value, str):
|
|
|
value = value.replace(',', '')
|
|
|
return temp.format(float(value))
|
|
|
elif isinstance(value, int) or isinstance(value, float):
|
|
|
return temp.format(value)
|
|
|
else:
|
|
|
return temp.format(0)
|
|
|
|
|
|
@staticmethod
|
|
|
def display_time(day_str, str_fmt="%Y-%m-%d %H:%M:%S"):
|
|
|
# 设置中文编码格式
|
|
|
# import locale
|
|
|
# locale.setlocale(locale.LC_CTYPE, 'chinese')
|
|
|
zh_fmt = '%Y年%m月%d日'
|
|
|
# en_fmt = '%B %d, %Y'
|
|
|
return time.strftime(zh_fmt, time.strptime(str(day_str), str_fmt))
|
|
|
|
|
|
def get_currency(self):
|
|
|
if self.kwargs.get("currency") == 'USD':
|
|
|
return "$"
|
|
|
return "¥"
|
|
|
|
|
|
def get_temple_number(self, number):
|
|
|
data = [
|
|
|
self.fill(number * 1.06),
|
|
|
self.fill(number),
|
|
|
self.fill(0),
|
|
|
self.fill(number * 0.06),
|
|
|
]
|
|
|
return data
|
|
|
|
|
|
@staticmethod
|
|
|
def check_path_creat(path):
|
|
|
if not os.path.exists(path):
|
|
|
os.mkdir(path)
|
|
|
|
|
|
|
|
|
class GenerateWordFromCSV(GenerateWord):
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
super().__init__(*args, **kwargs)
|
|
|
self.csv_list = []
|
|
|
self.total = 0
|
|
|
self.credit_total = 0
|
|
|
self.es_total = 0
|
|
|
self.linked_dict = dict()
|
|
|
self.filepath = list(self.kwargs['csv_list'])[0][:-4]
|
|
|
self.init_csv_list()
|
|
|
|
|
|
def init_csv_list(self):
|
|
|
for i in self.kwargs['csv_list']:
|
|
|
#self.csv_list.append(os.path.join(data_dir, i))
|
|
|
self.csv_list.append(i)
|
|
|
|
|
|
def data_mergence(self):
|
|
|
df = pd.DataFrame()
|
|
|
for csv in self.csv_list:
|
|
|
csv_data = pd.read_csv(
|
|
|
csv,
|
|
|
sep=',',
|
|
|
encoding='utf-8',
|
|
|
header=None,
|
|
|
names=csv_columns2,
|
|
|
dtype=data_type)
|
|
|
df = pd.concat([df, csv_data], axis=0)
|
|
|
df.reset_index(drop=True)
|
|
|
return df
|
|
|
|
|
|
def get_data_form_csv(self):
|
|
|
df = self.data_mergence()
|
|
|
df['CostBeforeTax'] = df['CostBeforeTax'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
df['Credits'] = df['Credits'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
df['TaxAmount'] = df['TaxAmount'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
df['TotalCost'] = df['TotalCost'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
lineitem_df = df[((df['RecordType'] == 'LinkedLineItem')
|
|
|
& (df['ItemDescription'] != '11-11 promotion for new-signup 3')
|
|
|
& (df['ItemDescription'] != '11-11 promotion for new-signup')
|
|
|
& (df['ItemDescription'] != 'PD 7180')
|
|
|
& (df['ItemDescription'] != 'PD 7398')
|
|
|
& (df['ProductName'] != 'Amazon Premium Support'))]
|
|
|
es_df = df[(df['RecordType'] == 'LinkedLineItem') & (
|
|
|
df['ProductName'] == 'Amazon Premium Support')]
|
|
|
credit_data = df[(df['RecordType'] == 'LinkedLineItem')
|
|
|
& ((df['ItemDescription'] == '11-11 promotion for new-signup 3')
|
|
|
| (df['ItemDescription'] == '11-11 promotion for new-signup')
|
|
|
| (df['ItemDescription'] == 'PD 7180')
|
|
|
| (df['ItemDescription'] == 'PD 7398'))
|
|
|
]
|
|
|
self.get_es_total(es_df)
|
|
|
self.get_credit_total(credit_data)
|
|
|
self.get_linkedaccount_dict(lineitem_df)
|
|
|
print('消费总额为{}'.format(self.total))
|
|
|
print('Credit总额为{}'.format(self.credit_total))
|
|
|
print('ES总额为{}'.format(self.es_total))
|
|
|
# self.save_mapping_date_to_csv()
|
|
|
# self.save_mapping()
|
|
|
for i in self.linked_dict:
|
|
|
self.linked_dict[i]['AWS Support (Enterprise)'] = \
|
|
|
self.linked_dict[i]['TotalCost'] / self.total * self.es_total
|
|
|
self.linked_dict[i]['AWS Credits'] = self.linked_dict[i]['TotalCost'] / \
|
|
|
self.total * self.credit_total
|
|
|
self.create_word(i)
|
|
|
|
|
|
def get_credit_total(self, data):
|
|
|
for i in range(data.shape[0]):
|
|
|
self.credit_total += float(data.iloc[i]['Credits'])
|
|
|
|
|
|
def get_es_total(self, data):
|
|
|
for i in range(data.shape[0]):
|
|
|
self.es_total += float(data.iloc[i]['CostBeforeTax'])
|
|
|
|
|
|
def get_linkedaccount_dict(self, data):
|
|
|
linked_set = set(data['LinkedAccountId'])
|
|
|
for i in range(data.shape[0]):
|
|
|
self.total += float(data.iloc[i]['CostBeforeTax'])
|
|
|
for i in linked_set:
|
|
|
linked_data = data[data['LinkedAccountId'] == i]
|
|
|
product_set = set(data['ProductName'])
|
|
|
linked_dict = {
|
|
|
'InvoiceID': linked_data.iloc[0]['InvoiceID'],
|
|
|
'TotalCost': linked_data['CostBeforeTax'].sum(),
|
|
|
}
|
|
|
for j in product_set:
|
|
|
linked_dict[j] = linked_data[linked_data['ProductName']
|
|
|
== j]['CostBeforeTax'].sum()
|
|
|
if i in self.linked_dict.keys():
|
|
|
for k, v in linked_dict.items():
|
|
|
if not k == 'InvoiceID':
|
|
|
product_num = self.linked_dict[i].get(k, 0)
|
|
|
self.linked_dict[i][k] = float(product_num) + float(v)
|
|
|
else:
|
|
|
self.linked_dict[i] = linked_dict
|
|
|
|
|
|
@staticmethod
|
|
|
def get_template():
|
|
|
return os.path.join(info_dir, 'china-template-2.docx')
|
|
|
|
|
|
def create_word(self, linked):
|
|
|
filedate, noticedate, due_data = from_filename_get_datetime(self.filepath)
|
|
|
result = self.linked_dict.get(linked, None)
|
|
|
if not result:
|
|
|
print('{}数据不存在'.format(linked))
|
|
|
invoiceid = result.pop('InvoiceID')
|
|
|
totalcost = result.pop('TotalCost')
|
|
|
product_code_dict = defaultdict()
|
|
|
for k, v in result.items():
|
|
|
product_code_dict[k] = super().get_temple_number(v)
|
|
|
totalcost_li = self.get_temple_number(totalcost)
|
|
|
date = self.get_date_array(filedate)
|
|
|
for i in range(len(date)):
|
|
|
date[i] = self.display_time(date[i], str_fmt="%Y-%m-%d")
|
|
|
xx = self.get_template()
|
|
|
template = DocxTemplate(xx)
|
|
|
content = {
|
|
|
'storage': self.get_storage(linked),
|
|
|
'linkedid': linked,
|
|
|
'noticenumber': invoiceid,
|
|
|
'noticedate': noticedate,
|
|
|
'currency': self.get_currency(),
|
|
|
'region_display': '北京区资源费',
|
|
|
'totalcost': totalcost_li,
|
|
|
'product_code_dict': product_code_dict,
|
|
|
'date': date,
|
|
|
'workday': due_data,
|
|
|
}
|
|
|
file_name = '{}{}_AWS账单{}.docx'.format(
|
|
|
self.get_storage(linked), linked, filedate)
|
|
|
doc_file_path = os.path.join(word_dir, self.filepath)
|
|
|
self.check_path_creat(doc_file_path)
|
|
|
doc_file_name = os.path.join(doc_file_path, file_name)
|
|
|
template.render(context=content)
|
|
|
template.save(doc_file_name)
|
|
|
print('{}{}_AWS账单{}.docx 生成完成'.format(self.get_storage(linked), linked, filedate))
|
|
|
|
|
|
@staticmethod
|
|
|
def get_storage(linkedid):
|
|
|
return ''
|
|
|
|
|
|
|
|
|
def get_temple_number(self, num):
|
|
|
data = [
|
|
|
self.fill(
|
|
|
((num / self.total * self.es_total) + num + num / self.total * self.credit_total) * 1.06),
|
|
|
self.fill(
|
|
|
(num / self.total * self.es_total) + num),
|
|
|
self.fill(
|
|
|
num / self.total * self.credit_total),
|
|
|
self.fill(
|
|
|
((num / self.total * self.es_total) + num + num / self.total * self.credit_total) * 0.06),
|
|
|
]
|
|
|
return data
|
|
|
|
|
|
class SamsungGenerateWordFromCSV(GenerateWordFromCSV):
|
|
|
|
|
|
def data_mergence(self):
|
|
|
# TODO 查看列
|
|
|
df = pd.DataFrame()
|
|
|
for csv in self.csv_list:
|
|
|
csv_data = pd.read_csv(
|
|
|
csv,
|
|
|
sep=',',
|
|
|
encoding='utf-8',
|
|
|
header=None,
|
|
|
names=csv_columns2,
|
|
|
dtype=data_type)
|
|
|
df = pd.concat([df, csv_data], axis=0)
|
|
|
df.reset_index(drop=True)
|
|
|
return df
|
|
|
|
|
|
def get_data_form_csv(self):
|
|
|
df = self.data_mergence()
|
|
|
df['CostBeforeTax'] = df['CostBeforeTax'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
df['TotalCost'] = df['TotalCost'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
lineitem_df = df[df['RecordType'] == 'LinkedLineItem']
|
|
|
|
|
|
self.get_linkedaccount_dict(lineitem_df)
|
|
|
print('消费总额为{}'.format(self.total))
|
|
|
discount = self.get_discount(self.total)
|
|
|
alicloud_dict = self.set_alicloud()
|
|
|
self.linked_dict.update(alicloud_dict)
|
|
|
ali_discount = 0.7
|
|
|
for k, v in self.linked_dict.items():
|
|
|
if k.isdigit():
|
|
|
for key, value in v.items():
|
|
|
if key != 'InvoiceID':
|
|
|
v[key] = ((value * 0.05 / discount) + value) * discount
|
|
|
else:
|
|
|
for key, value in v.items():
|
|
|
if key != 'InvoiceID':
|
|
|
_value = value / 1.06
|
|
|
v[key] = ((_value * 0.05 / ali_discount) + _value) * ali_discount
|
|
|
print(self.linked_dict)
|
|
|
SamsungGenerateWord(filename=self.filepath, link_dict=self.linked_dict).create_word()
|
|
|
|
|
|
@staticmethod
|
|
|
def get_discount(total):
|
|
|
discount_dict = {
|
|
|
(0, 100000): 0.99,
|
|
|
(100000, 200000): 0.988,
|
|
|
(200000, 300000): 0.986,
|
|
|
(300000, 10000000): 0.985,
|
|
|
}
|
|
|
for k, v in discount_dict.items():
|
|
|
if k[0] < total <= k[1]:
|
|
|
return v
|
|
|
return 0
|
|
|
|
|
|
@staticmethod
|
|
|
def set_alicloud():
|
|
|
return {
|
|
|
# 'lsm_stg' : {
|
|
|
# '云服务器ECS-包年包月': 77.68,
|
|
|
# '云服务器ECS-包年包月1': 1060.25,
|
|
|
# '云服务器ECS-快照': 0,
|
|
|
# '日志服务': 188.15,
|
|
|
# '负载均衡': 163.68,
|
|
|
# '关系型数据库RDS(包月)': 45.00,
|
|
|
# '云数据库KvStore-包年包月': 25.00,
|
|
|
# '对象存储OSS': 0,
|
|
|
# '消息队列RocketMQ版': 62.00,
|
|
|
# 'NAT网关(按量付费)': 372.00,
|
|
|
# '弹性公网IP': 14.90,
|
|
|
# '云服务器ECS-按量付费': 0,
|
|
|
# '弹性容器实例ECI': 3.31,
|
|
|
# '云监控按量付费': 32.71,
|
|
|
# 'TotalCost': 2044.68,
|
|
|
# 'InvoiceID': ''
|
|
|
# },
|
|
|
# 'lsm_prod':{
|
|
|
# 'Web应用防火墙(按量计费)': 372.00,
|
|
|
# '云服务器ECS-包年包月': 73.51,
|
|
|
# '云服务器ECS-包年包月1': 4426.00,
|
|
|
# '日志服务': 4069.47,
|
|
|
# '负载均衡': 580.32,
|
|
|
# '关系型数据库RDS(包月)': 1472.00,
|
|
|
# '云数据库KvStore-包年包月': 660.00,
|
|
|
# '对象存储OSS': 443.71,
|
|
|
# '消息队列RocketMQ版': 61.50,
|
|
|
# 'NAT网关(按量付费)': 1705.76,
|
|
|
# '密钥管理服务': 66.45,
|
|
|
# '共享流量包': 5428.80,
|
|
|
# '弹性公网IP': 29.76,
|
|
|
# '容器服务ACK': 476.16,
|
|
|
# '云监控按量付费': 0.60,
|
|
|
# 'TotalCost': 19866.04,
|
|
|
# 'InvoiceID': ''
|
|
|
# }
|
|
|
# 'lsm_stg': {
|
|
|
# 'NAT网关(按量付费)': 247.5,
|
|
|
# '传统型负载均衡CLB(按量付费)': 108.9,
|
|
|
# '弹性公网IP(后付费)': 9.96,
|
|
|
# '对象存储OSS': 0,
|
|
|
# '关系型数据库RDS(包月)': 45,
|
|
|
# '链路追踪': 0,
|
|
|
# '日志服务': 120.71,
|
|
|
# '消息队列 RocketMQ 版': 42,
|
|
|
# '云服务器ECS(包月)': 784.86,
|
|
|
# '云监控按量付费': 0,
|
|
|
# '云数据库KVStore版(包月)': 25,
|
|
|
# 'TotalCost': 1383.93,
|
|
|
# 'InvoiceID': ''
|
|
|
# },
|
|
|
# 'lsm_prod': {
|
|
|
# 'NAT网关(按量付费)': 1089.25,
|
|
|
# 'Web应用防火墙(按量计费)': 264,
|
|
|
# '传统型负载均衡CLB(按量付费)': 386.1,
|
|
|
# '弹性公网IP(后付费)': 19.8,
|
|
|
# '对象存储OSS': 288.02,
|
|
|
# '共享流量包': 7690.8,
|
|
|
# '密钥管理服务': 44.32,
|
|
|
# '日志服务': 2743.23,
|
|
|
# '容器服务ACK': 316.8,
|
|
|
# '消息队列 RocketMQ 版': 41.5,
|
|
|
# '云服务器ECS(包月)': 4480.96,
|
|
|
# '云监控按量付费': 0.6,
|
|
|
# 'TotalCost': 17365.38,
|
|
|
# 'InvoiceID': ''
|
|
|
# }
|
|
|
}
|
|
|
|
|
|
def aggregation_data_to_csv(self):
|
|
|
df = self.data_mergence()
|
|
|
df['CostBeforeTax'] = df['CostBeforeTax'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
df['TotalCost'] = df['TotalCost'].apply(
|
|
|
pd.to_numeric, errors='coerce').fillna(0.0)
|
|
|
lineitem_df = df[df['RecordType'] == 'LinkedLineItem']
|
|
|
self.total = lineitem_df['CostBeforeTax'].sum()
|
|
|
discount = self.get_discount(self.total)
|
|
|
data_df = lineitem_df.groupby(by=['LinkedAccountId', 'ProductName']).agg({'CostBeforeTax': 'sum'})
|
|
|
data_df['CostBeforeTax'] = data_df['CostBeforeTax'].apply(lambda x: ((x * 0.05 / discount) + x) * discount)
|
|
|
filepath = os.path.join(pivot_data_dir, self.filepath + '.csv')
|
|
|
data_df.to_csv(filepath, mode='w', encoding='UTF-8', quoting=1)
|
|
|
print('{}分析完成'.format(filepath))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
# 获取输入执行时输入参数
|
|
|
month = '2024-06'
|
|
|
if len(sys.argv) > 1:
|
|
|
month = sys.argv[1]
|
|
|
print('执行月份:' + month)
|
|
|
|
|
|
csv_list = ['089027636324-aws-cost-allocation-ACTS-'+month+'.csv',
|
|
|
'089027636324-aws-cost-allocation-ACTS-Ningxia-'+month+'.csv']
|
|
|
# 1.1 循环附件名
|
|
|
for csv in csv_list:
|
|
|
# print(os.path.isfile('./'+csv))
|
|
|
# 1.1.1附件不存在,则拉取
|
|
|
if not os.path.isfile('./' + csv):
|
|
|
print('附件不存在:', csv)
|
|
|
auto_download_file_form_s3([csv])
|
|
|
|
|
|
csv_typle = (
|
|
|
'089027636324-aws-cost-allocation-ACTS-'+month+'.csv',
|
|
|
'089027636324-aws-cost-allocation-ACTS-Ningxia-'+month+'.csv',
|
|
|
)
|
|
|
|
|
|
SamsungGenerateWordFromCSV(csv_list=csv_typle).get_data_form_csv()
|
|
|
SamsungGenerateWordFromCSV(csv_list=csv_typle).aggregation_data_to_csv()
|