# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# +
from tabulate import tabulate
from sagas.crmsfa.odoo_facade import odoo, login
import sagas.crmsfa.odoo_info as info
from sagas.tool.app_settings import setup_logger, setup_jupyter

setup_logger('crmsfa.log')
setup_jupyter()
# -

# ?login

login(db='demo', username='admin', password='<PASSWORD>')
info.desc_model("crm.lead")

# * 显示所有的潜在客户和他们的电子邮件

# +
model_name="crm.lead"

Model = odoo.env[model_name]
model_ids = Model.search([])
print(model_ids)
for record in Model.browse(model_ids):
    print(getattr(record, "name"), getattr(record, "email_from"))
# -

# * 查找指定邮件地址的客户(限制返回记录数为1)

lead_ids = Model.search([('email_from', '=', '<EMAIL>')], limit=1)
print(lead_ids)     
leads = Model.browse(lead_ids)
print(leads)
print(leads[0])
for lead in leads:
    print(lead.id, lead.name, type(lead.tag_ids))
    for tag in lead.tag_ids:
        print("\t", tag.name)

# * 日历事件

Model = odoo.env["calendar.event"]
model_ids = Model.search([])
print("total", len(model_ids))
for rec in Model.browse(model_ids):
    # <class 'datetime.datetime'>
    print(rec.id, rec.start, rec.stop, rec.duration)

# +
import dateparser
import time
# procs-dateparser.md
print(dateparser.parse('1 hour ago'))
print(dateparser.parse(u'2小时前'))
print(dateparser.parse(u'2018年11月1日'))
print(dateparser.parse(u'2018年12月30日'))
print(time.strftime('%Y-%m-05 12:00:00'))

#⊕ [python - How to overcome "datetime.datetime not JSON serializable"? - Stack Overflow](https://stackoverflow.com/questions/11875770/how-to-overcome-datetime-datetime-not-json-serializable)
from datetime import date, datetime
from json import dumps

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

print(dumps(datetime.now(), default=json_serial))
# -

# * 查找指定日期范围内的记录

a_date=str(dateparser.parse(u'2018年11月1日'))
b_date=str(dateparser.parse(u'2018年12月10日'))
# procs-odoo-orm-api.md
#⊕ [Get list of ids - Odoo - Stack Overflow](https://stackoverflow.com/questions/45839212/get-list-of-ids-odoo)
# ev_recs = Model.search([('start','<=',b_date),('start','>=',a_date)]).ids
ev_recs = Model.search([('start','<=',b_date),('start','>=',a_date)])
print(len(ev_recs))

# * 图查询(使用graphql)
# * 这一部分需要先了解graphql协议, 以及使用graphene库来支持graphql的查询和更新功能
# * 相对来说比较复杂, 之后会专门演练graphql

# +
import graphene
class CrmLead(graphene.ObjectType):
    name = graphene.String()
    email_from=graphene.String()
    
class Query(graphene.ObjectType):
    crm_lead = graphene.Field(CrmLead, email_from=graphene.String())
    crm_leads = graphene.List(CrmLead)
    
    def resolve_crm_lead(self, info, email_from):
        return get_crm_lead(email_from)
    def resolve_crm_leads(self, info):
        model_name="crm.lead"
        Model = odoo.env[model_name]
        model_ids = Model.search([])
        recordset=[]
        for record in Model.browse(model_ids):
            recordset.append(CrmLead(name=getattr(record, "name"), 
                                     email_from=getattr(record, "email_from")))
        return recordset
    
def get_crm_lead(sent):
    model_name="crm.lead"
    Model = odoo.env[model_name]
    lead_ids = Model.search([('email_from', '=', sent)], limit=1)   
    leads = Model.browse(lead_ids)
    assert len(leads)==1
    # print(leads)
    lead=leads[0]
    return CrmLead(name=lead.name, email_from=lead.email_from)

schema = graphene.Schema(query=Query)     
# -

import json
default_query = '''
query FetchCrmLead($sent: String!) {
      crmLead(emailFrom: $sent) {
        name
        emailFrom
      }
    }
'''.strip()
variables = {"sent":"<EMAIL>"}
result = schema.execute(default_query, variables=variables)
print(json.dumps(result.data, indent=2, ensure_ascii=False))

default_query = '''
{
  crmLeads {
    name
    emailFrom
  }
}
'''.strip()
result = schema.execute(default_query)
print(json.dumps(result.data, indent=2, ensure_ascii=False))

info.desc_model("calendar.event")

# +
import graphene
from odoorpc.fields import Many2many, Many2one, One2many, Unknown
TYPES_TO_FIELDS = {
    'binary': graphene.String,
    'boolean': graphene.Boolean,
    'char': graphene.String,
    'date': graphene.types.datetime.Date,
    'datetime': graphene.types.datetime.DateTime,
    'float': graphene.Float,
    'html': graphene.String,
    'integer': graphene.Int,
    
    #⊕ [Graphene-Python](http://docs.graphene-python.org/en/latest/types/scalars/#custom-scalars)
    'many2many': Many2many,
    'many2one': Many2one,
    'one2many': One2many,
    
    'reference': graphene.String,
    'selection': graphene.String,
    'text': graphene.String,
}

def generate_field(name, data):
    """Generate a well-typed field according to the data dictionary supplied
    (obtained via the `fields_get' method of any models).
    """
    assert 'type' in data
    field = TYPES_TO_FIELDS.get(data['type'], Unknown)()
    return field


# -

field = TYPES_TO_FIELDS.get("date", Unknown)()
print(type(field))


# +
# from graphene.utils.str_converters import to_camel_case, to_snake_case

def to_camel_case(snake_str):
    components = snake_str.split("_")
    # We capitalize the first letter of each component except the first one
    # with the 'capitalize' method and join them together.
    return "".join(x.capitalize() if x else "_" for x in components[:])

def normalize_class(model):
    cls_name = model.replace('.', '_')
    return to_camel_case(cls_name)
print(normalize_class("calendar.event"))

# +
from odoorpc.env import FIELDS_RESERVED
import odoorpc.fields as fields

model="calendar.event"
attrs = {
        '_name': model,
        '_columns': {},
    }
def get_recurrent_fields():
    return ['byday', 'recurrency', 'final_date', 'rrule_type', 'month_by',
            'interval', 'count', 'end_type', 'mo', 'tu', 'we', 'th', 'fr', 'sa',
            'su', 'day', 'week_list']
fields_get = odoo.execute(model, 'fields_get')
for field_name, field_data in fields_get.items():
    field_type=field_data['type']
    if field_name not in FIELDS_RESERVED and \
        field_name not in get_recurrent_fields() and \
        not field_name.startswith("_") and \
        field_type not in ("many2many","many2one","one2many"):
            
        Field = fields.generate_field(field_name, field_data)
        FieldType=generate_field(field_name, field_data)
        attrs['_columns'][field_name] = Field
        attrs[field_name] = FieldType
        print(field_name, type(FieldType))

cls_name=normalize_class(model)
print(".. create class", cls_name)
model_cls=type(cls_name, (graphene.ObjectType,), attrs)
# -

for fld in model_cls._columns.keys():
    print(fld)

# +
import inspect

def desc_type(type_name):
    # attributes = inspect.getmembers(type(type_name), lambda a:not(inspect.isroutine(a)))
    attributes = inspect.getmembers(type_name, lambda a:not(inspect.isroutine(a)))    
    fields=[a for a in attributes 
            if not(a[0].startswith('__') 
                   and a[0].endswith('__'))]
    for f in fields:
        if f[0]!="_columns":
            print(f)    

desc_type(model_cls)

# +
import graphene

def create_with_attrs(model_cls, record):
    inst=model_cls()
    for fld in model_cls._columns.keys():
        val=getattr(record, fld)
        setattr(inst, fld, val)
    return inst

model_name="calendar.event"
of_type=model_cls

class CalQuery(graphene.ObjectType):
    calendar_event = graphene.List(of_type)
    
    def resolve_calendar_event(self, info):        
        Model = odoo.env[model_name]
        model_ids = Model.search([])
        recordset=[]
        for record in Model.browse(model_ids):
            recordset.append(create_with_attrs(of_type, record))
        return recordset

schema = graphene.Schema(query=CalQuery)    
print(of_type)
# -

default_query = '''
{
  calendarEvent {
    name
    description
    start
  }
}
'''.strip()
result = schema.execute(default_query)
print(json.dumps(result.data, indent=2, ensure_ascii=False))

StarcoderdataJupyterScriptsDedupFiltered