diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d9581ca..b8064c7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,7 @@ dev: added methods: - dump_db: wrapper around ``db.dump`` server method. - restore_db: wrapper around ``db.restore`` server methods. + - ``openerp_proxy.ext.repr.HField`` added ``F()`` method, which allows to create child field instance 0.6: - *Backward incompatible*: Changed session file format. diff --git a/examples/Examples & HTML tests.ipynb b/examples/Examples & HTML tests.ipynb index 5b7a511..3b1839e 100644 --- a/examples/Examples & HTML tests.ipynb +++ b/examples/Examples & HTML tests.ipynb @@ -233,7 +233,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 7, @@ -272,7 +272,7 @@ "\n" ], "text/plain": [ - "" + "" ] }, "execution_count": 8, @@ -575,7 +575,7 @@ " 'help': 'The tax amount.',\n", " 'readonly': 1,\n", " 'selectable': True,\n", - " 'store': \"{'sale.order': ( at 0x77fd0c8>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", + " 'store': \"{'sale.order': ( at 0x6e8f0c8>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", " 'string': 'Taxes',\n", " 'type': 'float'},\n", " 'amount_total': {'digits': [16, 2],\n", @@ -586,7 +586,7 @@ " 'help': 'The total amount.',\n", " 'readonly': 1,\n", " 'selectable': True,\n", - " 'store': \"{'sale.order': ( at 0x77fd1b8>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", + " 'store': \"{'sale.order': ( at 0x6e8f1b8>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", " 'string': 'Total',\n", " 'type': 'float'},\n", " 'amount_untaxed': {'digits': [16, 2],\n", @@ -597,7 +597,7 @@ " 'help': 'The amount without tax.',\n", " 'readonly': 1,\n", " 'selectable': True,\n", - " 'store': \"{'sale.order': ( at 0x77edf50>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", + " 'store': \"{'sale.order': ( at 0x6e7ff50>, ['order_line'], 10), 'sale.order.line': (, ['price_unit', 'tax_id', 'discount', 'product_uom_qty'], 10)}\",\n", " 'string': 'Untaxed Amount',\n", " 'type': 'float'},\n", " 'client_order_ref': {'selectable': True,\n", @@ -1009,7 +1009,7 @@ { "data": { "text/html": [ - "
Note, that You may use .to_csv() method of this table to export it to CSV format
RecordList(sale.order): length=8
idnamePartner namePartner emailorder_line.as_html_listRelated Invoicesstate
8SO008Millennium IndustriesFalse
  • 20: Laptop Customized
  • 21: Mouse, Wireless
    draft
    7SO007Luminous TechnologiesFalse
    • 16: Laptop E5023
    • 17: GrapWorks Software
    • 18: Datacard
    • 19: USB Adapter
      manual
      6SO006Think Big Systemsinfo@thinkbig.com
      • 15: PC Assamble + 2GB RAM
        draft
        5SO005Agrolaitinfo@agrolait.com
        • 12: External Hard disk
        • 13: Blank DVD-RW
        • 14: Printer, All-in-one
          draft
          4SO004Millennium IndustriesFalse
          • 8: Service on demand
          • 9: Webcam
          • 10: Multimedia Speakers
          • 11: Switch, 24 ports
            draft
            3SO003Chamber Worksinfo@chamberworks.com
            • 6: On Site Monitoring
            • 7: Toner Cartridge
              draft
              2SO002Bank Wealthy and sonsemail@wealthyandsons.com
              • 4: Service on demand
              • 5: On Site Assistance
                draft
                1SO001Agrolaitinfo@agrolait.com
                • 1: Laptop E5023
                • 2: Pen drive, 16GB
                • 3: Headset USB
                  done
                  " + "
                  Note, that You may use .to_csv() method of this table to export it to CSV format
                  RecordList(sale.order): length=8
                  idnamePartner namePartner emailOrder linesstate
                  8SO008Millennium IndustriesFalse
                  • 20: Laptop Customized
                  • 21: Mouse, Wireless
                  draft
                  7SO007Luminous TechnologiesFalse
                  • 16: Laptop E5023
                  • 17: GrapWorks Software
                  • 18: Datacard
                  • 19: USB Adapter
                  manual
                  6SO006Think Big Systemsinfo@thinkbig.com
                  • 15: PC Assamble + 2GB RAM
                  draft
                  5SO005Agrolaitinfo@agrolait.com
                  • 12: External Hard disk
                  • 13: Blank DVD-RW
                  • 14: Printer, All-in-one
                  draft
                  4SO004Millennium IndustriesFalse
                  • 8: Service on demand
                  • 9: Webcam
                  • 10: Multimedia Speakers
                  • 11: Switch, 24 ports
                  draft
                  3SO003Chamber Worksinfo@chamberworks.com
                  • 6: On Site Monitoring
                  • 7: Toner Cartridge
                  draft
                  2SO002Bank Wealthy and sonsemail@wealthyandsons.com
                  • 4: Service on demand
                  • 5: On Site Assistance
                  draft
                  1SO001Agrolaitinfo@agrolait.com
                  • 1: Laptop E5023
                  • 2: Pen drive, 16GB
                  • 3: Headset USB
                  manual
                  " ], "text/plain": [ "" @@ -1042,9 +1042,7 @@ " HField('partner_id.email', name='Partner email', silent=True),\n", " # Also it is posible to display result of method calls\n", " # 'as_html_list()' is method of RecordList.\n", - " 'order_line.as_html_list',\n", - " # Argument can be passed as tuple, (field, field name)\n", - " ('invoice_ids.as_html_list', 'Related Invoices'),\n", + " ('order_line.as_html_list', 'Order lines'),\n", " 'state',\n", " highlighters=highlighters,\n", ")\n", @@ -1068,10 +1066,10 @@ { "data": { "text/html": [ - "tmp/csv/tmpTw7Sgq.csv
                  " + "tmp/csv/tmpnMWowr.csv
                  " ], "text/plain": [ - "/home/katyukha/projects/erp-proxy/examples/tmp/csv/tmpTw7Sgq.csv" + "/home/katyukha/projects/erp-proxy/examples/tmp/csv/tmpnMWowr.csv" ] }, "execution_count": 20, @@ -1103,7 +1101,7 @@ "\n", "
                  \n", "
                  \n", - "
                  R(sale.order, 8)[SO008]
                  ObjectObject ('sale.order')
                  Proxyxml-rpc://admin@localhost:8069/openerp_proxy_test_db
                  NameSO008
                  \n", + "
                  R(sale.order, 8)[SO008]
                  ObjectObject ('sale.order')
                  Proxyxml-rpc://admin@localhost:8069/openerp_proxy_test_db
                  ID8
                  NameSO008
                  \n", "
                  \n", "
                  To get HTML Table representation of this record call method:
                   .as_html()
                  Optionaly You can pass list of fields You want to see:
                   .as_html('name', 'origin')
                  for better information get doc on as_html method:
                   .as_html?
                  \n", "
                  \n" @@ -1167,7 +1165,7 @@ { "data": { "text/html": [ - "
                  Record SO008
                  ColumnValue
                  Confirmation DateFalse
                  Contract / AnalyticFalse
                  Create Invoicemanual
                  Creation Date2015-09-08 10:58:27
                  CustomerR(res.partner, 19)[Millennium Industries]
                  Customer ReferenceFalse
                  Date2015-09-08
                  Delivery AddressR(res.partner, 52)[Millennium Industries, Jacob Taylor]
                  Fiscal PositionFalse
                  Invoice AddressR(res.partner, 52)[Millennium Industries, Jacob Taylor]
                  Invoice onorder
                  InvoicesRecordList(account.invoice): length=0
                  MessagesRecordList(mail.message): length=2
                  Order LinesRecordList(sale.order.line): length=2
                  Order ReferenceSO008
                  Payment TermFalse
                  PricelistR(product.pricelist, 1)[Public Pricelist (EUR)]
                  SalespersonR(res.users, 3)[Demo User]
                  ShopR(sale.shop, 1)[Your Company]
                  Source DocumentFalse
                  Statusdraft
                  Terms and conditionsFalse
                  " + "
                  Record SO008
                  ColumnValue
                  Confirmation DateFalse
                  Contract / AnalyticFalse
                  Create Invoicemanual
                  Creation Date2015-10-01 15:08:09
                  CustomerR(res.partner, 19)[Millennium Industries]
                  Customer ReferenceFalse
                  Date2015-10-01
                  Delivery AddressR(res.partner, 52)[Millennium Industries, Jacob Taylor]
                  Fiscal PositionFalse
                  Invoice AddressR(res.partner, 52)[Millennium Industries, Jacob Taylor]
                  Invoice onorder
                  InvoicesRecordList(account.invoice): length=0
                  MessagesRecordList(mail.message): length=2
                  Order LinesRecordList(sale.order.line): length=2
                  Order ReferenceSO008
                  Payment TermFalse
                  PricelistR(product.pricelist, 1)[Public Pricelist (EUR)]
                  SalespersonR(res.users, 3)[Demo User]
                  ShopR(sale.shop, 1)[Your Company]
                  Source DocumentFalse
                  Statusdraft
                  Terms and conditionsFalse
                  " ], "text/plain": [ "" @@ -1217,7 +1215,7 @@ "
                  This is report service.
                  To get list of available reports
                  You can access available_reports
                  property of this service:
                  .available_reports
                  " ], "text/plain": [ - "" + "" ] }, "execution_count": 24, @@ -1249,33 +1247,33 @@ "
                  Note, that You may use .to_csv() method of this table to export it to CSV format
                  Available reports
                  report service namereport namereport modelreport help info
                  account.account.balanceTrial Balanceaccount.accountFalse
                  account.analytic.account.balanceAnalytic Balanceaccount.analytic.accountFalse
                  account.analytic.account.cost_ledgerCost Ledgeraccount.analytic.accountFalse
                  account.analytic.account.inverted.balanceInverted Analytic Balanceaccount.analytic.accountFalse
                  account.analytic.account.journalAnalytic Journalaccount.analytic.journalFalse
                  account.analytic.account.quantity_cost_ledgerCost Ledger (Only quantities)account.analytic.accountFalse
                  account.central.journalCentral Journalaccount.journal.periodFalse
                  account.general.journalGeneral Journalaccount.journal.periodFalse
                  account.general.ledgerGeneral Ledgeraccount.accountFalse
                  account.general.ledger_landscapeGeneral Ledgeraccount.accountFalse
                  account.intracomIntraComaccount.move.lineFalse
                  account.invoiceInvoicesaccount.invoiceFalse
                  account.journal.period.printJournalaccount.journal.periodFalse
                  account.journal.period.print.sale.purchaseSale/Purchase Journalaccount.journal.periodFalse
                  account.overdueDue Paymentsres.partnerFalse
                  account.partner.balancePartner Balanceaccount.accountFalse
                  account.third_party_ledgerPartner Ledgerres.partnerFalse
                  account.third_party_ledger_otherPartner Ledgerres.partnerFalse
                  account.transferTransfersaccount.transferFalse
                  account.vat.declarationTaxes Reportaccount.tax.codeFalse
                  ir.model.overviewModel Overviewir.modelFalse
                  ir.module.referenceTechnical guideir.module.moduleFalse
                  preview.reportPreview Reportres.companyFalse
                  product.pricelistPricelistproduct.productFalse
                  product.product.labelProducts Labelsproduct.productFalse
                  res.partnerLabelsres.partnerFalse
                  sale.orderQuotation / Ordersale.orderFalse
                  " ], "text/plain": [ - "{'account.account.balance': ,\n", - " 'account.analytic.account.balance': ,\n", - " 'account.analytic.account.cost_ledger': ,\n", - " 'account.analytic.account.inverted.balance': ,\n", - " 'account.analytic.account.journal': ,\n", - " 'account.analytic.account.quantity_cost_ledger': ,\n", - " 'account.central.journal': ,\n", - " 'account.general.journal': ,\n", - " 'account.general.ledger': ,\n", - " 'account.general.ledger_landscape': ,\n", - " 'account.intracom': ,\n", - " 'account.invoice': ,\n", - " 'account.journal.period.print': ,\n", - " 'account.journal.period.print.sale.purchase': ,\n", - " 'account.overdue': ,\n", - " 'account.partner.balance': ,\n", - " 'account.third_party_ledger': ,\n", - " 'account.third_party_ledger_other': ,\n", - " 'account.transfer': ,\n", - " 'account.vat.declaration': ,\n", - " 'ir.model.overview': ,\n", - " 'ir.module.reference': ,\n", - " 'preview.report': ,\n", - " 'product.pricelist': ,\n", - " 'product.product.label': ,\n", - " 'res.partner': ,\n", - " 'sale.order': }" + "{'account.account.balance': ,\n", + " 'account.analytic.account.balance': ,\n", + " 'account.analytic.account.cost_ledger': ,\n", + " 'account.analytic.account.inverted.balance': ,\n", + " 'account.analytic.account.journal': ,\n", + " 'account.analytic.account.quantity_cost_ledger': ,\n", + " 'account.central.journal': ,\n", + " 'account.general.journal': ,\n", + " 'account.general.ledger': ,\n", + " 'account.general.ledger_landscape': ,\n", + " 'account.intracom': ,\n", + " 'account.invoice': ,\n", + " 'account.journal.period.print': ,\n", + " 'account.journal.period.print.sale.purchase': ,\n", + " 'account.overdue': ,\n", + " 'account.partner.balance': ,\n", + " 'account.third_party_ledger': ,\n", + " 'account.third_party_ledger_other': ,\n", + " 'account.transfer': ,\n", + " 'account.vat.declaration': ,\n", + " 'ir.model.overview': ,\n", + " 'ir.module.reference': ,\n", + " 'preview.report': ,\n", + " 'product.pricelist': ,\n", + " 'product.product.label': ,\n", + " 'res.partner': ,\n", + " 'sale.order': }" ] }, "execution_count": 25, @@ -1291,7 +1289,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Take a look on report object. It also has it's own HTML representation." + "Choose report name for current Odoo server version" ] }, { @@ -1300,6 +1298,41 @@ "metadata": { "collapsed": false }, + "outputs": [ + { + "data": { + "text/plain": [ + "'sale.order'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from pkg_resources import parse_version as V\n", + "if ldb.server_version > V(\"7.0\"):\n", + " report_name = 'sale.report_saleorder'\n", + "else:\n", + " report_name = 'sale.order'\n", + "\n", + "report_name" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Take a look on report object. It also has it's own HTML representation." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, "outputs": [ { "data": { @@ -1307,22 +1340,23 @@ "\n", "
                  \n", "
                  \n", - "
                  Report Labels
                  NameLabels
                  Service nameres.partner
                  Modelres.partner
                  \n", + "
                  Report Quotation / Order
                  NameQuotation / Order
                  Service namesale.order
                  Modelsale.order
                  \n", "
                  \n", "
                  This is report representation.
                  call generate method to generate new report
                   .generate([1, 2, 3])
                  Also generate method can receive
                  RecordList or Record instance as first argument.
                  For more information look in documentation
                  \n", "
                  \n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 26, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "ldb.services.report['res.partner']" + "report = ldb.services.report[report_name]\n", + "report" ] }, { @@ -1334,7 +1368,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 28, "metadata": { "collapsed": false }, @@ -1342,21 +1376,20 @@ { "data": { "text/html": [ - "tmp/reports/Labels851fd3b45adb12d1c7b6dd96d105635ead8c664c91aecc5772f1d482bd94a60b.pdf
                  " + "tmp/reports/Quotation - Order3eff4a1fc2fabfd0106063c1e41416d9347bf34f82681baa083abf3294d9532d.pdf
                  " ], "text/plain": [ - "" + "" ] }, - "execution_count": 27, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# Generate report named 'Labels' (report service name is 'res.partner')\n", - "report = ldb.services.report['res.partner'].generate(ldb._res_partner([]))\n", - "report" + "report_result = report.generate(so_list)\n", + "report_result" ] } ], diff --git a/openerp_proxy/ext/repr.py b/openerp_proxy/ext/repr.py index 3ff340f..6387763 100644 --- a/openerp_proxy/ext/repr.py +++ b/openerp_proxy/ext/repr.py @@ -11,21 +11,21 @@ import csv import os.path import tempfile +from IPython.display import HTML, FileLink -from openerp_proxy import (Client, - Session) -from openerp_proxy.orm import (RecordList, - Record, - Object) -from openerp_proxy.service.report import (Report, - ReportResult, - ReportService) +from .. import (Client, + Session) +from ..orm import (RecordList, + Record, + Object) +from ..service.report import (Report, + ReportResult, + ReportService) -from IPython.display import HTML, FileLink -from openerp_proxy.utils import ustr as _ -from openerp_proxy.utils import (AttrDict, - makedirs) +from ..utils import ustr as _ +from ..utils import (AttrDict, + makedirs) # TODO: use enviroment var or some sort of config @@ -87,14 +87,15 @@ def dict_to_html_table_info(data, caption='', help='', table_styles=''): class FieldNotFoundException(Exception): """ Exception raised when HField cannot find field in object been processed """ - def __init__(self, obj, field, original_exc=None): - self.field = field + def __init__(self, obj, name, hfield, original_exc=None): + self.hfield = hfield + self.name = name self.obj = obj self.orig_exc = original_exc @property def message(self): - return u"Field %s not found in obj %s" % (_(self.field), _(self.obj)) + return u"Field %s not found in obj %s while calculation hfield %s" % (_(self.field), _(self.obj), self.hfield) # TODO: implement correct behavior. It fails in IPython notebook with # UnicodeEncodeError because of python's standard warnings module @@ -125,6 +126,9 @@ class HField(object): :param bool silent: If set to True, then not exceptions will be raised and *default* value will be returned. (default=False) :param default: default value to be returned if field not found. default=None + :param HField parent: (for internal usage) parent field. First get value of parent field + for record, and then get value of current field based on value + of parent field: ( self.get_field(self._parent.get_field(record)) ) :param args: if specified, then it means that field is callable, and *args* should be passed to it as positional arguments. This may be useful to call *as_html_table* method of internal field. for example:: @@ -144,14 +148,32 @@ class HField(object): :param dict kwargs: same as *args* but for keyword arguments """ - def __init__(self, field, name=None, silent=False, default=None, args=None, kwargs=None): + def __init__(self, field, name=None, silent=False, default=None, parent=None, args=None, kwargs=None): self._field = field self._name = name self._silent = silent self._default = default + self._parent = parent self._args = tuple() if args is None else args self._kwargs = dict() if kwargs is None else kwargs + def F(self, field, **kwargs): + """ Create chained field + Could be used for complicated field. + for example:: + + HField('myfield.myvalue', default={'a': 5}).F('a') + """ + return HField( + field, + parent=self, + name=kwargs.get('name', self._name), + silent=kwargs.get('silent', self._silent), + default=kwargs.get('default', self._default), + args=kwargs.get('args', self._args), + kwargs=kwargs.get('kwargs', self._kwargs), + ) + def with_args(self, *args, **kwargs): """ If field is string pointing to function (or method), all arguments and keyword arguments passed to this method, @@ -194,7 +216,11 @@ def get_field(self, record): :type record: Record :return: requested value """ + # process parent field + if self._parent is not None: + record = self._parent.get_field(record) + # check if field is callable if callable(self._field): return self._field(record, *self._args, **self._kwargs)