def portal_my_dms_directory(self, dms_directory_id=False, sortby=None, filterby=None, search=None, search_in="name", access_token=None, **kw): """Process user's consent acceptance or rejection.""" ensure_db() try: # If there's a website, we need a user to render the template request.uid = request.website.user_id.id except AttributeError: # If there's no website, the default is OK pass # operations searchbar_sortings = { "name": { "label": _("Name"), "order": "name asc" } } # default sortby br if not sortby: sortby = "name" sort_br = searchbar_sortings[sortby]["order"] # search searchbar_inputs = { "name": { "input": "name", "label": _("Name") }, } if not filterby: filterby = "name" # domain domain = [("is_hidden", "=", False), ("parent_id", "=", dms_directory_id)] # search if search and search_in: search_domain = [] if search_in == "name": search_domain = OR( [search_domain, [("name", "ilike", search)]]) domain += search_domain # content according to pager and archive selected dms_directory_items = (request.env["dms.directory"].with_user( request.env.user.id).search(domain, order=sort_br)) request.session["my_dms_folder_history"] = dms_directory_items.ids # check_access res = self._dms_check_access("dms.directory", dms_directory_id, access_token) if not res: if access_token: return request.redirect("/") else: return request.redirect("/my") dms_directory_sudo = res # dms_files_count domain = [ ("is_hidden", "=", False), ("directory_id", "=", dms_directory_id), ] # search if search and search_in: search_domain = [] if search_in == "name": search_domain = OR( [search_domain, [("name", "ilike", search)]]) domain += search_domain # items dms_file_items = (request.env["dms.file"].with_user( request.env.user.id).search(domain, order=sort_br)) request.session["my_dms_file_history"] = dms_file_items.ids dms_parent_categories = dms_directory_sudo.with_user( request.env.user.id)._get_parent_categories(access_token) # values values = { "dms_directories": dms_directory_items.sudo(), "page_name": "dms_directory", "default_url": "/my/dms", "searchbar_sortings": searchbar_sortings, "searchbar_inputs": searchbar_inputs, "search_in": search_in, "sortby": sortby, "filterby": filterby, "access_token": access_token, "dms_directory": dms_directory_sudo, "dms_files": dms_file_items.sudo(), "dms_parent_categories": dms_parent_categories, } return request.render("dms.portal_my_dms", values)
def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw): groupby = kw.get('groupby', 'project') #TODO master fix this values = self._prepare_portal_layout_values() searchbar_sortings = { 'date': { 'label': _('Newest'), 'order': 'create_date desc' }, 'name': { 'label': _('Title'), 'order': 'name' }, 'stage': { 'label': _('Stage'), 'order': 'stage_id' }, 'update': { 'label': _('Last Stage Update'), 'order': 'date_last_stage_update desc' }, } searchbar_filters = { 'all': { 'label': _('All'), 'domain': [] }, } searchbar_inputs = { 'content': { 'input': 'content', 'label': _('Search <span class="nolabel"> (in Content)</span>') }, 'message': { 'input': 'message', 'label': _('Search in Messages') }, 'customer': { 'input': 'customer', 'label': _('Search in Customer') }, 'stage': { 'input': 'stage', 'label': _('Search in Stages') }, 'all': { 'input': 'all', 'label': _('Search in All') }, } searchbar_groupby = { 'none': { 'input': 'none', 'label': _('None') }, 'project': { 'input': 'project', 'label': _('Project') }, } # extends filterby criteria with project (criteria name is the project id) # Note: portal users can't view projects they don't follow partner = request.env.user.partner_id domain_projects = [ '&', ('privacy_visibility', '=', 'portal'), '|', ('message_partner_ids', 'child_of', [partner.commercial_partner_id.id]), ('task_ids.message_partner_ids', 'child_of', [partner.commercial_partner_id.id]) ] projects = request.env['project.project'].sudo().search( domain_projects) domain = [('project_id', 'in', projects.ids)] for proj in projects: searchbar_filters.update({ str(proj.id): { 'label': proj.name, 'domain': [('project_id', '=', proj.id)] } }) # default sort by value if not sortby: sortby = 'date' order = searchbar_sortings[sortby]['order'] # default filter by value if not filterby: filterby = 'all' domain += searchbar_filters[filterby]['domain'] # archive groups - Default Group By 'create_date' archive_groups = self._get_archive_groups('project.task', domain) if date_begin and date_end: domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)] # search if search and search_in: search_domain = [] if search_in in ('content', 'all'): search_domain = OR([ search_domain, [ '|', ('name', 'ilike', search), ('description', 'ilike', search) ] ]) if search_in in ('customer', 'all'): search_domain = OR( [search_domain, [('partner_id', 'ilike', search)]]) if search_in in ('message', 'all'): search_domain = OR( [search_domain, [('message_ids.body', 'ilike', search)]]) if search_in in ('stage', 'all'): search_domain = OR( [search_domain, [('stage_id', 'ilike', search)]]) domain += search_domain # task count task_count = request.env['project.task'].search_count(domain) # pager pager = portal_pager(url="/my/tasks", url_args={ 'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby, 'filterby': filterby, 'search_in': search_in, 'search': search }, total=task_count, page=page, step=self._items_per_page) # content according to pager and archive selected if groupby == 'project': order = "project_id, %s" % order # force sort on project first to group by project in view tasks = request.env['project.task'].search(domain, order=order, limit=self._items_per_page, offset=(page - 1) * self._items_per_page) request.session['my_tasks_history'] = tasks.ids[:100] if groupby == 'project': grouped_tasks = [ request.env['project.task'].concat(*g) for k, g in groupbyelem(tasks, itemgetter('project_id')) ] else: grouped_tasks = [tasks] values.update({ 'date': date_begin, 'date_end': date_end, 'projects': projects, 'tasks': tasks, 'grouped_tasks': grouped_tasks, 'page_name': 'task', 'archive_groups': archive_groups, 'default_url': '/my/tasks', 'pager': pager, 'searchbar_sortings': searchbar_sortings, 'searchbar_groupby': searchbar_groupby, 'searchbar_inputs': searchbar_inputs, 'search_in': search_in, 'sortby': sortby, 'groupby': groupby, 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), 'filterby': filterby, }) return request.render("project.portal_my_tasks", values)
def _import_fattura_pa(self, tree, invoice): """ Decodes a fattura_pa invoice into an invoice. :param tree: the fattura_pa tree to decode. :param invoice: the invoice to update or an empty recordset. :returns: the invoice where the fattura_pa data was imported. """ invoices = self.env['account.move'] first_run = True # possible to have multiple invoices in the case of an invoice batch, the batch itself is repeated for every invoice of the batch for body_tree in tree.xpath('//FatturaElettronicaBody'): if not first_run or not invoice: # make sure all the iterations create a new invoice record (except the first which could have already created one) invoice = self.env['account.move'] first_run = False # Type must be present in the context to get the right behavior of the _default_journal method (account.move). # journal_id must be present in the context to get the right behavior of the _default_account method (account.move.line). elements = tree.xpath('//CessionarioCommittente//IdCodice') company = elements and self.env['res.company'].search( [('vat', 'ilike', elements[0].text)], limit=1) if not company: elements = tree.xpath( '//CessionarioCommittente//CodiceFiscale') company = elements and self.env['res.company'].search( [('l10n_it_codice_fiscale', 'ilike', elements[0].text)], limit=1) if not company: # Only invoices with a correct VAT or Codice Fiscale can be imported _logger.warning( 'No company found with VAT or Codice Fiscale like %r.', elements[0].text) continue # Refund type. # TD01 == invoice # TD02 == advance/down payment on invoice # TD03 == advance/down payment on fee # TD04 == credit note # TD05 == debit note # TD06 == fee # For unsupported document types, just assume in_invoice, and log that the type is unsupported elements = tree.xpath('//DatiGeneraliDocumento/TipoDocumento') move_type = 'in_invoice' if elements and elements[0].text and elements[0].text == 'TD04': move_type = 'in_refund' elif elements and elements[0].text and elements[0].text != 'TD01': _logger.info( 'Document type not managed: %s. Invoice type is set by default.', elements[0].text) # Setup the context for the Invoice Form invoice_ctx = invoice.with_company(company) \ .with_context(default_move_type=move_type) # move could be a single record (editing) or be empty (new). with Form(invoice_ctx) as invoice_form: message_to_log = [] # Partner (first step to avoid warning 'Warning! You must first select a partner.'). <1.2> elements = tree.xpath('//CedentePrestatore//IdCodice') partner = elements and self.env['res.partner'].search([ '&', ('vat', 'ilike', elements[0].text), '|', ('company_id', '=', company.id), ('company_id', '=', False) ], limit=1) if not partner: elements = tree.xpath('//CedentePrestatore//CodiceFiscale') if elements: codice = elements[0].text domains = [[('l10n_it_codice_fiscale', '=', codice)]] if re.match(r'^[0-9]{11}$', codice): domains.append([('l10n_it_codice_fiscale', '=', 'IT' + codice)]) elif re.match(r'^IT[0-9]{11}$', codice): domains.append([ ('l10n_it_codice_fiscale', '=', self.env['res.partner']. _l10n_it_normalize_codice_fiscale(codice)) ]) partner = elements and self.env['res.partner'].search( AND([ OR(domains), OR([[('company_id', '=', company.id)], [('company_id', '=', False)]]) ]), limit=1) if not partner: elements = tree.xpath('//DatiTrasmissione//Email') partner = elements and self.env['res.partner'].search( [ '&', '|', ('email', '=', elements[0].text), ('l10n_it_pec_email', '=', elements[0].text), '|', ('company_id', '=', company.id), ('company_id', '=', False) ], limit=1) if partner: invoice_form.partner_id = partner else: message_to_log.append("%s<br/>%s" % ( _("Vendor not found, useful informations from XML file:" ), invoice._compose_info_message(tree, './/CedentePrestatore'))) # Numbering attributed by the transmitter. <1.1.2> elements = tree.xpath('//ProgressivoInvio') if elements: invoice_form.payment_reference = elements[0].text elements = body_tree.xpath('.//DatiGeneraliDocumento//Numero') if elements: invoice_form.ref = elements[0].text # Currency. <2.1.1.2> elements = body_tree.xpath('.//DatiGeneraliDocumento/Divisa') if elements: currency_str = elements[0].text currency = self.env.ref('base.%s' % currency_str.upper(), raise_if_not_found=False) if currency != self.env.company.currency_id and currency.active: invoice_form.currency_id = currency # Date. <2.1.1.3> elements = body_tree.xpath('.//DatiGeneraliDocumento/Data') if elements: date_str = elements[0].text date_obj = datetime.strptime( date_str, DEFAULT_FACTUR_ITALIAN_DATE_FORMAT) invoice_form.invoice_date = date_obj # Dati Bollo. <2.1.1.6> elements = body_tree.xpath( './/DatiGeneraliDocumento/DatiBollo/ImportoBollo') if elements: invoice_form.l10n_it_stamp_duty = float(elements[0].text) # List of all amount discount (will be add after all article to avoid to have a negative sum) discount_list = [] percentage_global_discount = 1.0 # Global discount. <2.1.1.8> discount_elements = body_tree.xpath( './/DatiGeneraliDocumento/ScontoMaggiorazione') total_discount_amount = 0.0 if discount_elements: for discount_element in discount_elements: discount_line = discount_element.xpath('.//Tipo') discount_sign = -1 if discount_line and discount_line[0].text == 'SC': discount_sign = 1 discount_percentage = discount_element.xpath( './/Percentuale') if discount_percentage and discount_percentage[0].text: percentage_global_discount *= 1 - float( discount_percentage[0].text ) / 100 * discount_sign discount_amount_text = discount_element.xpath( './/Importo') if discount_amount_text and discount_amount_text[ 0].text: discount_amount = float(discount_amount_text[0]. text) * discount_sign * -1 discount = {} discount["seq"] = 0 if discount_amount < 0: discount["name"] = _('GLOBAL DISCOUNT') else: discount["name"] = _('GLOBAL EXTRA CHARGE') discount["amount"] = discount_amount discount["tax"] = [] discount_list.append(discount) # Comment. <2.1.1.11> elements = body_tree.xpath('.//DatiGeneraliDocumento//Causale') for element in elements: invoice_form.narration = '%s%s\n' % (invoice_form.narration or '', element.text) # Informations relative to the purchase order, the contract, the agreement, # the reception phase or invoices previously transmitted # <2.1.2> - <2.1.6> for document_type in [ 'DatiOrdineAcquisto', 'DatiContratto', 'DatiConvenzione', 'DatiRicezione', 'DatiFattureCollegate' ]: elements = body_tree.xpath('.//DatiGenerali/' + document_type) if elements: for element in elements: message_to_log.append( "%s %s<br/>%s" % (document_type, _("from XML file:"), invoice._compose_info_message(element, '.'))) # Dati DDT. <2.1.8> elements = body_tree.xpath('.//DatiGenerali/DatiDDT') if elements: message_to_log.append( "%s<br/>%s" % (_("Transport informations from XML file:"), invoice._compose_info_message( body_tree, './/DatiGenerali/DatiDDT'))) # Due date. <2.4.2.5> elements = body_tree.xpath( './/DatiPagamento/DettaglioPagamento/DataScadenzaPagamento' ) if elements: date_str = elements[0].text date_obj = datetime.strptime( date_str, DEFAULT_FACTUR_ITALIAN_DATE_FORMAT) invoice_form.invoice_date_due = fields.Date.to_string( date_obj) # Total amount. <2.4.2.6> elements = body_tree.xpath('.//ImportoPagamento') amount_total_import = 0 for element in elements: amount_total_import += float(element.text) if amount_total_import: message_to_log.append( _("Total amount from the XML File: %s") % (amount_total_import)) # Bank account. <2.4.2.13> if invoice_form.move_type not in ('out_invoice', 'in_refund'): elements = body_tree.xpath( './/DatiPagamento/DettaglioPagamento/IBAN') if elements: if invoice_form.partner_id and invoice_form.partner_id.commercial_partner_id: bank = self.env['res.partner.bank'].search([ ('acc_number', '=', elements[0].text), ('partner_id.id', '=', invoice_form.partner_id. commercial_partner_id.id) ]) else: bank = self.env['res.partner.bank'].search([ ('acc_number', '=', elements[0].text) ]) if bank: invoice_form.partner_bank_id = bank else: message_to_log.append("%s<br/>%s" % ( _("Bank account not found, useful informations from XML file:" ), invoice._compose_multi_info_message( body_tree, [ './/DatiPagamento//Beneficiario', './/DatiPagamento//IstitutoFinanziario', './/DatiPagamento//IBAN', './/DatiPagamento//ABI', './/DatiPagamento//CAB', './/DatiPagamento//BIC', './/DatiPagamento//ModalitaPagamento' ]))) else: elements = body_tree.xpath( './/DatiPagamento/DettaglioPagamento') if elements: message_to_log.append("%s<br/>%s" % ( _("Bank account not found, useful informations from XML file:" ), invoice._compose_info_message( body_tree, './/DatiPagamento'))) # Invoice lines. <2.2.1> elements = body_tree.xpath('.//DettaglioLinee') if elements: for element in elements: with invoice_form.invoice_line_ids.new( ) as invoice_line_form: # Sequence. line_elements = element.xpath('.//NumeroLinea') if line_elements: invoice_line_form.sequence = int( line_elements[0].text) * 2 # Product. line_elements = element.xpath('.//Descrizione') if line_elements: invoice_line_form.name = " ".join( line_elements[0].text.split()) elements_code = element.xpath('.//CodiceArticolo') if elements_code: for element_code in elements_code: type_code = element_code.xpath( './/CodiceTipo')[0] code = element_code.xpath( './/CodiceValore')[0] if type_code.text == 'EAN': product = self.env[ 'product.product'].search([ ('barcode', '=', code.text) ]) if product: invoice_line_form.product_id = product break if partner: product_supplier = self.env[ 'product.supplierinfo'].search([ ('name', '=', partner.id), ('product_code', '=', code.text) ]) if product_supplier and product_supplier.product_id: invoice_line_form.product_id = product_supplier.product_id break if not invoice_line_form.product_id: for element_code in elements_code: code = element_code.xpath( './/CodiceValore')[0] product = self.env[ 'product.product'].search( [('default_code', '=', code.text)], limit=1) if product: invoice_line_form.product_id = product break # Price Unit. line_elements = element.xpath('.//PrezzoUnitario') if line_elements: invoice_line_form.price_unit = float( line_elements[0].text) # Quantity. line_elements = element.xpath('.//Quantita') if line_elements: invoice_line_form.quantity = float( line_elements[0].text) else: invoice_line_form.quantity = 1 # Taxes tax_element = element.xpath('.//AliquotaIVA') natura_element = element.xpath('.//Natura') invoice_line_form.tax_ids.clear() if tax_element and tax_element[0].text: percentage = float(tax_element[0].text) if natura_element and natura_element[0].text: l10n_it_kind_exoneration = natura_element[ 0].text tax = self.env['account.tax'].search( [ ('company_id', '=', invoice_form.company_id.id), ('amount_type', '=', 'percent'), ('type_tax_use', '=', 'purchase'), ('amount', '=', percentage), ('l10n_it_kind_exoneration', '=', l10n_it_kind_exoneration), ], limit=1) else: tax = self.env['account.tax'].search( [ ('company_id', '=', invoice_form.company_id.id), ('amount_type', '=', 'percent'), ('type_tax_use', '=', 'purchase'), ('amount', '=', percentage), ], limit=1) l10n_it_kind_exoneration = '' if tax: invoice_line_form.tax_ids.add(tax) else: if l10n_it_kind_exoneration: message_to_log.append( _("Tax not found with percentage: %s and exoneration %s for the article: %s" ) % (percentage, l10n_it_kind_exoneration, invoice_line_form.name)) else: message_to_log.append( _("Tax not found with percentage: %s for the article: %s" ) % (percentage, invoice_line_form.name)) # Discount in cascade mode. # if 3 discounts : -10% -50€ -20% # the result must be : (((price -10%)-50€) -20%) # Generic form : (((price -P1%)-A1€) -P2%) # It will be split in two parts: fix amount and pourcent amount # example: (((((price - A1€) -P2%) -A3€) -A4€) -P5€) # pourcent: 1-(1-P2)*(1-P5) # fix amount: A1*(1-P2)*(1-P5)+A3*(1-P5)+A4*(1-P5) (we must take account of all # percentage present after the fix amount) line_elements = element.xpath( './/ScontoMaggiorazione') total_discount_amount = 0.0 total_discount_percentage = percentage_global_discount if line_elements: for line_element in line_elements: discount_line = line_element.xpath( './/Tipo') discount_sign = -1 if discount_line and discount_line[ 0].text == 'SC': discount_sign = 1 discount_percentage = line_element.xpath( './/Percentuale') if discount_percentage and discount_percentage[ 0].text: pourcentage_actual = 1 - float( discount_percentage[0].text ) / 100 * discount_sign total_discount_percentage *= pourcentage_actual total_discount_amount *= pourcentage_actual discount_amount = line_element.xpath( './/Importo') if discount_amount and discount_amount[ 0].text: total_discount_amount += float( discount_amount[0].text ) * discount_sign * -1 # Save amount discount. if total_discount_amount != 0: discount = {} discount[ "seq"] = invoice_line_form.sequence + 1 if total_discount_amount < 0: discount["name"] = _( 'DISCOUNT: %s', invoice_line_form.name) else: discount["name"] = _( 'EXTRA CHARGE: %s', invoice_line_form.name) discount["amount"] = total_discount_amount discount["tax"] = [] for tax in invoice_line_form.tax_ids: discount["tax"].append(tax) discount_list.append(discount) invoice_line_form.discount = ( 1 - total_discount_percentage) * 100 # Apply amount discount. for discount in discount_list: with invoice_form.invoice_line_ids.new( ) as invoice_line_form_discount: invoice_line_form_discount.tax_ids.clear() invoice_line_form_discount.sequence = discount["seq"] invoice_line_form_discount.name = discount["name"] invoice_line_form_discount.price_unit = discount[ "amount"] new_invoice = invoice_form.save() new_invoice.l10n_it_send_state = "other" elements = body_tree.xpath('.//Allegati') if elements: for element in elements: name_attachment = element.xpath( './/NomeAttachment')[0].text attachment_64 = str.encode( element.xpath('.//Attachment')[0].text) attachment_64 = self.env['ir.attachment'].create({ 'name': name_attachment, 'datas': attachment_64, 'type': 'binary', }) # default_res_id is had to context to avoid facturx to import his content # no_new_invoice to prevent from looping on the message_post that would create a new invoice without it new_invoice.with_context( no_new_invoice=True, default_res_id=new_invoice.id).message_post( body=(_("Attachment from XML")), attachment_ids=[attachment_64.id]) for message in message_to_log: new_invoice.message_post(body=message) invoices += new_invoice return invoices
def _get_translation_frontend_modules_domain(cls): domain = super(Http, cls)._get_translation_frontend_modules_domain() return OR([domain, [('name', 'ilike', 'website')]])
def my_tickets(self, page=1, start_date=None, end_date=None, sort=None, search=None, in_search='content', **kw): result = self._prepare_portal_layout_values() domain = self._get_tickets_domain(request.env.user.partner_id) sortings = { 'name': { 'label': _('Subject'), 'order': 'name' }, 'date': { 'label': _('Newest'), 'order': 'create_date desc' }, 'stage': { 'label': _('Stage'), 'order': 'stage_id' }, } if not sort: sort = 'date' order = sortings[sort]['order'] archive_groups = self._get_archive_groups('supportdesk.ticket', domain) if start_date and end_date: domain += [('create_date', '>', start_date), ('create_date', '<=', end_date)] if search and in_search: in_search_filter = [] if in_search in ('customer', 'all'): in_search_filter = OR( [in_search_filter, [('partner_id', 'ilike', search)]]) if in_search in ('content', 'all'): in_search_filter = OR([ in_search_filter, [ '|', ('name', 'ilike', search), ('description', 'ilike', search) ] ]) if in_search in ('stage', 'all'): in_search_filter = OR( [in_search_filter, [('stage_id', 'ilike', search)]]) if in_search in ('message', 'all'): in_search_filter = OR([ in_search_filter, [('message_ids.body', 'ilike', search)] ]) domain += in_search_filter support_tickets_count = request.env['supportdesk.ticket'].search_count( domain) pager = portal_pager(url="/my/support_tickets", url_args={ 'start_date': start_date, 'end_date': end_date, 'sortby': sort }, total=support_tickets_count, page=page, step=self._items_per_page) support_tickets = request.env['supportdesk.ticket'].sudo().search( domain, order=order, limit=self._items_per_page, offset=pager['offset']) request.session['my_tickets_history'] = support_tickets.ids[:50] result.update({ 'page_name': 'ticket', 'pager': pager, 'date': start_date, 'tickets': support_tickets, 'default_url': '/my/support_tickets', 'sortby': sort, 'search_in': in_search, 'search': search, 'searchbar_sortings': sortings, 'archive_groups': archive_groups, }) return request.render("support_desk.portal_support_ticket", result)
def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', **kw): values = self._prepare_portal_layout_values() domain = [('project_id.privacy_visibility', '=', 'portal')] searchbar_sortings = { 'date': { 'label': _('Newest'), 'order': 'create_date desc' }, 'name': { 'label': _('Title'), 'order': 'name' }, 'stage': { 'label': _('Stage'), 'order': 'stage_id' }, 'update': { 'label': _('Last Stage Update'), 'order': 'date_last_stage_update desc' }, } searchbar_filters = { 'all': { 'label': _('All'), 'domain': [] }, } searchbar_inputs = { 'content': { 'input': 'content', 'label': _('Search <span class="nolabel"> (in Content)</span>') }, 'message': { 'input': 'message', 'label': _('Search in Messages') }, 'customer': { 'input': 'customer', 'label': _('Search in Customer') }, 'stage': { 'input': 'stage', 'label': _('Search in Stages') }, 'all': { 'input': 'all', 'label': _('Search in All') }, } # extends filterby criteria with project (criteria name is the project id) projects = request.env['project.project'].search([ ('privacy_visibility', '=', 'portal') ]) for proj in projects: searchbar_filters.update({ str(proj.id): { 'label': proj.name, 'domain': [('project_id', '=', proj.id)] } }) # default sort by value if not sortby: sortby = 'date' order = searchbar_sortings[sortby]['order'] # default filter by value if not filterby: filterby = 'all' domain += searchbar_filters[filterby]['domain'] # archive groups - Default Group By 'create_date' archive_groups = self._get_archive_groups('project.task', domain) if date_begin and date_end: domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)] # search if search and search_in: search_domain = [] if search_in in ('content', 'all'): search_domain = OR([ search_domain, [ '|', ('name', 'ilike', search), ('description', 'ilike', search) ] ]) if search_in in ('customer', 'all'): search_domain = OR( [search_domain, [('partner_id', 'ilike', search)]]) if search_in in ('message', 'all'): search_domain = OR( [search_domain, [('message_ids.body', 'ilike', search)]]) if search_in in ('stage', 'all'): search_domain = OR( [search_domain, [('stage_id', 'ilike', search)]]) domain += search_domain # task count task_count = request.env['project.task'].search_count(domain) # pager pager = portal_pager(url="/my/tasks", url_args={ 'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby, 'filterby': filterby }, total=task_count, page=page, step=self._items_per_page) # content according to pager and archive selected tasks = request.env['project.task'].search(domain, order=order, limit=self._items_per_page, offset=pager['offset']) request.session['my_tasks_history'] = tasks.ids[:100] values.update({ 'date': date_begin, 'date_end': date_end, 'projects': projects, 'tasks': tasks, 'page_name': 'task', 'archive_groups': archive_groups, 'default_url': '/my/tasks', 'pager': pager, 'searchbar_sortings': searchbar_sortings, 'searchbar_inputs': searchbar_inputs, 'search_in': search_in, 'sortby': sortby, 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), 'filterby': filterby, }) return request.render("project.portal_my_tasks", values)
def portal_my_tasks(self, page=1, date_begin=None, date_end=None, sortby=None, filterby=None, search=None, search_in='content', groupby=None, **kw): values = self._prepare_portal_layout_values() searchbar_sortings = { 'date': {'label': _('Newest'), 'order': 'create_date desc'}, 'name': {'label': _('Title'), 'order': 'name'}, 'stage': {'label': _('Stage'), 'order': 'stage_id, project_id'}, 'project': {'label': _('Project'), 'order': 'project_id, stage_id'}, 'update': {'label': _('Last Stage Update'), 'order': 'date_last_stage_update desc'}, } searchbar_filters = { 'all': {'label': _('All'), 'domain': []}, } searchbar_inputs = { 'content': {'input': 'content', 'label': _('Search <span class="nolabel"> (in Content)</span>')}, 'message': {'input': 'message', 'label': _('Search in Messages')}, 'customer': {'input': 'customer', 'label': _('Search in Customer')}, 'stage': {'input': 'stage', 'label': _('Search in Stages')}, 'project': {'input': 'project', 'label': _('Search in Project')}, 'all': {'input': 'all', 'label': _('Search in All')}, } searchbar_groupby = { 'none': {'input': 'none', 'label': _('None')}, 'project': {'input': 'project', 'label': _('Project')}, 'stage': {'input': 'stage', 'label': _('Stage')}, } # extends filterby criteria with project the customer has access to projects = request.env['project.project'].search([]) for project in projects: searchbar_filters.update({ str(project.id): {'label': project.name, 'domain': [('project_id', '=', project.id)]} }) # extends filterby criteria with project (criteria name is the project id) # Note: portal users can't view projects they don't follow project_groups = request.env['project.task'].read_group([('project_id', 'not in', projects.ids)], ['project_id'], ['project_id']) for group in project_groups: proj_id = group['project_id'][0] if group['project_id'] else False proj_name = group['project_id'][1] if group['project_id'] else _('Others') searchbar_filters.update({ str(proj_id): {'label': proj_name, 'domain': [('project_id', '=', proj_id)]} }) # default sort by value if not sortby: sortby = 'date' order = searchbar_sortings[sortby]['order'] # default filter by value if not filterby: filterby = 'all' domain = searchbar_filters.get(filterby, searchbar_filters.get('all'))['domain'] # default group by value if not groupby: groupby = 'project' if date_begin and date_end: domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)] # search if search and search_in: search_domain = [] if search_in in ('content', 'all'): search_domain = OR([search_domain, ['|', ('name', 'ilike', search), ('description', 'ilike', search)]]) if search_in in ('customer', 'all'): search_domain = OR([search_domain, [('partner_id', 'ilike', search)]]) if search_in in ('message', 'all'): search_domain = OR([search_domain, [('message_ids.body', 'ilike', search)]]) if search_in in ('stage', 'all'): search_domain = OR([search_domain, [('stage_id', 'ilike', search)]]) if search_in in ('project', 'all'): search_domain = OR([search_domain, [('project_id', 'ilike', search)]]) domain += search_domain # task count task_count = request.env['project.task'].search_count(domain) # pager pager = portal_pager( url="/my/tasks", url_args={'date_begin': date_begin, 'date_end': date_end, 'sortby': sortby, 'filterby': filterby, 'groupby': groupby, 'search_in': search_in, 'search': search}, total=task_count, page=page, step=self._items_per_page ) # content according to pager and archive selected if groupby == 'project': order = "project_id, %s" % order # force sort on project first to group by project in view elif groupby == 'stage': order = "stage_id, %s" % order # force sort on stage first to group by stage in view tasks = request.env['project.task'].search(domain, order=order, limit=self._items_per_page, offset=pager['offset']) request.session['my_tasks_history'] = tasks.ids[:100] if groupby == 'project': grouped_tasks = [request.env['project.task'].concat(*g) for k, g in groupbyelem(tasks, itemgetter('project_id'))] elif groupby == 'stage': grouped_tasks = [request.env['project.task'].concat(*g) for k, g in groupbyelem(tasks, itemgetter('stage_id'))] else: grouped_tasks = [tasks] values.update({ 'date': date_begin, 'date_end': date_end, 'grouped_tasks': grouped_tasks, 'page_name': 'task', 'default_url': '/my/tasks', 'pager': pager, 'searchbar_sortings': searchbar_sortings, 'searchbar_groupby': searchbar_groupby, 'searchbar_inputs': searchbar_inputs, 'search_in': search_in, 'search': search, 'sortby': sortby, 'groupby': groupby, 'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), 'filterby': filterby, }) return request.render("project.portal_my_tasks", values)