[MERGE] forward port branch 11.0 up to b1d43cc80e
This commit is contained in:
@@ -675,6 +675,9 @@
|
|||||||
help="Opportunities that are assigned to me"/>
|
help="Opportunities that are assigned to me"/>
|
||||||
<filter string="Unassigned" name="unassigned"
|
<filter string="Unassigned" name="unassigned"
|
||||||
domain="[('user_id','=', False)]" help="No salesperson"/>
|
domain="[('user_id','=', False)]" help="No salesperson"/>
|
||||||
|
<filter string="Open Opportunities" name="open_opportunities"
|
||||||
|
domain="[('probability', '<', 100), ('type', '=', 'opportunity')]"
|
||||||
|
help="Open Opportunities"/>
|
||||||
<separator/>
|
<separator/>
|
||||||
<filter string="Activities Todo" name="activities_my"
|
<filter string="Activities Todo" name="activities_my"
|
||||||
domain="[('activity_ids.user_id', '=', uid)]"/>
|
domain="[('activity_ids.user_id', '=', uid)]"/>
|
||||||
|
|||||||
@@ -204,7 +204,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row" t-if="record.opportunities_count.raw_value">
|
<div class="row" t-if="record.opportunities_count.raw_value">
|
||||||
<div class="col-xs-8">
|
<div class="col-xs-8">
|
||||||
<a name="%(crm_case_form_view_salesteams_opportunity)d" type="action"> <!-- context="{'search_default_probability': NOT or < 100}" -->
|
<a name="%(crm_case_form_view_salesteams_opportunity)d" type="action" context="{'search_default_open_opportunities': True}"> <!-- context="{'search_default_probability': NOT or < 100}" -->
|
||||||
<field name="opportunities_count"/>
|
<field name="opportunities_count"/>
|
||||||
<t t-if="record.opportunities_count.raw_value == 1">Open Opportunity</t>
|
<t t-if="record.opportunities_count.raw_value == 1">Open Opportunity</t>
|
||||||
<t t-else="">Open Opportunities</t>
|
<t t-else="">Open Opportunities</t>
|
||||||
|
|||||||
@@ -306,7 +306,9 @@ class AccountFrFec(models.TransientModel):
|
|||||||
END
|
END
|
||||||
AS PieceRef,
|
AS PieceRef,
|
||||||
TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate,
|
TO_CHAR(am.date, 'YYYYMMDD') AS PieceDate,
|
||||||
CASE WHEN aml.name IS NULL OR aml.name = '' THEN '/' ELSE replace(replace(aml.name, '|', '/'), '\t', '') END AS EcritureLib,
|
CASE WHEN aml.name IS NULL OR aml.name = '' THEN '/'
|
||||||
|
WHEN aml.name SIMILAR TO '[\t|\s|\n]*' THEN '/'
|
||||||
|
ELSE replace(replace(replace(aml.name, '|', '/'), '\t', ''), '\n', '') END AS EcritureLib,
|
||||||
replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE to_char(aml.debit, '000000000000000D99') END, '.', ',') AS Debit,
|
replace(CASE WHEN aml.debit = 0 THEN '0,00' ELSE to_char(aml.debit, '000000000000000D99') END, '.', ',') AS Debit,
|
||||||
replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE to_char(aml.credit, '000000000000000D99') END, '.', ',') AS Credit,
|
replace(CASE WHEN aml.credit = 0 THEN '0,00' ELSE to_char(aml.credit, '000000000000000D99') END, '.', ',') AS Credit,
|
||||||
CASE WHEN rec.name IS NULL THEN '' ELSE rec.name END AS EcritureLet,
|
CASE WHEN rec.name IS NULL THEN '' ELSE rec.name END AS EcritureLet,
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
'name': 'Support Services',
|
'name': 'Support Services',
|
||||||
'price_unit': 25.50,
|
'price_unit': 25.50,
|
||||||
'product_qty': 10.0,
|
'product_qty': 10.0,
|
||||||
'product_uom': ref('uom.product_uom_unit'),
|
'product_uom': ref('uom.product_uom_hour'),
|
||||||
'date_planned': time.strftime('%Y-%m-%d')}),
|
'date_planned': time.strftime('%Y-%m-%d')}),
|
||||||
]"/>
|
]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class CrmTeam(models.Model):
|
|||||||
def _compute_sales_to_invoice(self):
|
def _compute_sales_to_invoice(self):
|
||||||
sale_order_data = self.env['sale.order'].read_group([
|
sale_order_data = self.env['sale.order'].read_group([
|
||||||
('team_id', 'in', self.ids),
|
('team_id', 'in', self.ids),
|
||||||
('order_line.qty_to_invoice', '>', 0),
|
('invoice_status','=','to invoice'),
|
||||||
], ['team_id'], ['team_id'])
|
], ['team_id'], ['team_id'])
|
||||||
for datum in sale_order_data:
|
for datum in sale_order_data:
|
||||||
self.browse(datum['team_id'][0]).sales_to_invoice_count = datum['team_id_count']
|
self.browse(datum['team_id'][0]).sales_to_invoice_count = datum['team_id_count']
|
||||||
|
|||||||
@@ -856,7 +856,7 @@
|
|||||||
<field name="view_type">form</field>
|
<field name="view_type">form</field>
|
||||||
<field name="view_mode">tree,form,calendar,graph,kanban,pivot</field>
|
<field name="view_mode">tree,form,calendar,graph,kanban,pivot</field>
|
||||||
<field name="search_view_id" ref="sale.sale_order_view_search_inherit_sale"/>
|
<field name="search_view_id" ref="sale.sale_order_view_search_inherit_sale"/>
|
||||||
<field name="domain">[('state', '=', 'sale'),('invoice_status','=','to invoice')]</field>
|
<field name="domain">[('invoice_status','=','to invoice')]</field>
|
||||||
<field name="context">{
|
<field name="context">{
|
||||||
'search_default_team_id': [active_id],
|
'search_default_team_id': [active_id],
|
||||||
'default_team_id': active_id,
|
'default_team_id': active_id,
|
||||||
|
|||||||
@@ -393,10 +393,12 @@ class StockMove(models.Model):
|
|||||||
receipt_moves_to_reassign = self.env['stock.move']
|
receipt_moves_to_reassign = self.env['stock.move']
|
||||||
if 'product_uom_qty' in vals:
|
if 'product_uom_qty' in vals:
|
||||||
for move in self.filtered(lambda m: m.state not in ('done', 'draft') and m.picking_id):
|
for move in self.filtered(lambda m: m.state not in ('done', 'draft') and m.picking_id):
|
||||||
if vals['product_uom_qty'] != move.product_uom_qty:
|
if float_compare(vals['product_uom_qty'], move.product_uom_qty, precision_rounding=move.product_uom.rounding):
|
||||||
self.env['stock.move.line']._log_message(move.picking_id, move, 'stock.track_move_template', vals)
|
self.env['stock.move.line']._log_message(move.picking_id, move, 'stock.track_move_template', vals)
|
||||||
if self.env.context.get('do_not_unreserve') is None:
|
if self.env.context.get('do_not_unreserve') is None:
|
||||||
move_to_unreserve = self.filtered(lambda m: m.state not in ['draft', 'done', 'cancel'] and m.reserved_availability > vals.get('product_uom_qty'))
|
move_to_unreserve = self.filtered(
|
||||||
|
lambda m: m.state not in ['draft', 'done', 'cancel'] and float_compare(m.reserved_availability, vals.get('product_uom_qty'), precision_rounding=m.product_uom.rounding) == 1
|
||||||
|
)
|
||||||
move_to_unreserve._do_unreserve()
|
move_to_unreserve._do_unreserve()
|
||||||
(self - move_to_unreserve).filtered(lambda m: m.state == 'assigned').write({'state': 'partially_available'})
|
(self - move_to_unreserve).filtered(lambda m: m.state == 'assigned').write({'state': 'partially_available'})
|
||||||
# When editing the initial demand, directly run again action assign on receipt moves.
|
# When editing the initial demand, directly run again action assign on receipt moves.
|
||||||
|
|||||||
@@ -276,7 +276,10 @@ class StockMoveLine(models.Model):
|
|||||||
# When editing a done move line, the reserved availability of a potential chained move is impacted. Take care of running again `_action_assign` on the concerned moves.
|
# When editing a done move line, the reserved availability of a potential chained move is impacted. Take care of running again `_action_assign` on the concerned moves.
|
||||||
next_moves = self.env['stock.move']
|
next_moves = self.env['stock.move']
|
||||||
if updates or 'qty_done' in vals:
|
if updates or 'qty_done' in vals:
|
||||||
for ml in self.filtered(lambda ml: ml.move_id.state == 'done' and ml.product_id.type == 'product'):
|
mls = self.filtered(lambda ml: ml.move_id.state == 'done' and ml.product_id.type == 'product')
|
||||||
|
if not updates: # we can skip those where qty_done is already good up to UoM rounding
|
||||||
|
mls = mls.filtered(lambda ml: not float_is_zero(ml.qty_done - vals['qty_done'], precision_rounding=ml.product_uom_id.rounding))
|
||||||
|
for ml in mls:
|
||||||
# undo the original move line
|
# undo the original move line
|
||||||
qty_done_orig = ml.move_id.product_uom._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
|
qty_done_orig = ml.move_id.product_uom._compute_quantity(ml.qty_done, ml.move_id.product_id.uom_id, rounding_method='HALF-UP')
|
||||||
in_date = Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -qty_done_orig, lot_id=ml.lot_id,
|
in_date = Quant._update_available_quantity(ml.product_id, ml.location_dest_id, -qty_done_orig, lot_id=ml.lot_id,
|
||||||
|
|||||||
@@ -158,7 +158,7 @@
|
|||||||
<button name="action_reset_product_qty" states="confirm" string="⇒ Set quantities to 0" type="object" class="oe_link oe_right" groups="stock.group_stock_user"/>
|
<button name="action_reset_product_qty" states="confirm" string="⇒ Set quantities to 0" type="object" class="oe_link oe_right" groups="stock.group_stock_user"/>
|
||||||
<field name="line_ids" string="Inventory Details" context="{'default_location_id': location_id, 'default_product_id': product_id, 'default_prod_lot_id': lot_id, 'default_package_id': package_id, 'default_partner_id': partner_id}" mode="tree,kanban">
|
<field name="line_ids" string="Inventory Details" context="{'default_location_id': location_id, 'default_product_id': product_id, 'default_prod_lot_id': lot_id, 'default_package_id': package_id, 'default_partner_id': partner_id}" mode="tree,kanban">
|
||||||
<tree string="Inventory Details" editable="bottom" decoration-info="product_qty != theoretical_qty" decoration-danger="theoretical_qty < 0">
|
<tree string="Inventory Details" editable="bottom" decoration-info="product_qty != theoretical_qty" decoration-danger="theoretical_qty < 0">
|
||||||
<field name="product_id" domain="[('type','=','product')]"/>
|
<field name="product_id" domain="[('type','=','product')]" attrs="{'readonly': [('parent.filter', '=', 'product')]}"/>
|
||||||
<field name="product_uom_id" string="UoM" groups="uom.group_uom"/>
|
<field name="product_uom_id" string="UoM" groups="uom.group_uom"/>
|
||||||
<field name="location_id" domain="[('id', 'child_of', parent.location_id)]" groups="stock.group_stock_multi_locations"/>
|
<field name="location_id" domain="[('id', 'child_of', parent.location_id)]" groups="stock.group_stock_multi_locations"/>
|
||||||
<field name="prod_lot_id" domain="[('product_id', '=', product_id)]" context="{'default_product_id': product_id}" groups="stock.group_production_lot"/>
|
<field name="prod_lot_id" domain="[('product_id', '=', product_id)]" context="{'default_product_id': product_id}" groups="stock.group_production_lot"/>
|
||||||
|
|||||||
@@ -88,7 +88,10 @@ class StockMoveLine(models.Model):
|
|||||||
if 'qty_done' in vals:
|
if 'qty_done' in vals:
|
||||||
moves_to_update = {}
|
moves_to_update = {}
|
||||||
for move_line in self.filtered(lambda ml: ml.state == 'done' and (ml.move_id._is_in() or ml.move_id._is_out())):
|
for move_line in self.filtered(lambda ml: ml.state == 'done' and (ml.move_id._is_in() or ml.move_id._is_out())):
|
||||||
moves_to_update[move_line.move_id] = vals['qty_done'] - move_line.qty_done
|
rounding = move_line.product_uom_id.rounding
|
||||||
|
qty_difference = float_round(vals['qty_done'] - move_line.qty_done, precision_rounding=rounding)
|
||||||
|
if not float_is_zero(qty_difference, precision_rounding=rounding):
|
||||||
|
moves_to_update[move_line.move_id] = qty_difference
|
||||||
|
|
||||||
for move_id, qty_difference in moves_to_update.items():
|
for move_id, qty_difference in moves_to_update.items():
|
||||||
move_vals = {}
|
move_vals = {}
|
||||||
|
|||||||
@@ -1317,7 +1317,7 @@ var FieldBinaryFile = AbstractFieldBinary.extend({
|
|||||||
'id': this.res_id,
|
'id': this.res_id,
|
||||||
'field': this.name,
|
'field': this.name,
|
||||||
'filename_field': filename_fieldname,
|
'filename_field': filename_fieldname,
|
||||||
'filename': this.recordData[filename_fieldname] || null,
|
'filename': this.recordData[filename_fieldname] || "",
|
||||||
'download': true,
|
'download': true,
|
||||||
'data': utils.is_bin_size(this.value) ? null : this.value,
|
'data': utils.is_bin_size(this.value) ? null : this.value,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -328,9 +328,9 @@ class IrHttp(models.AbstractModel):
|
|||||||
if not filename:
|
if not filename:
|
||||||
if filename_field in obj:
|
if filename_field in obj:
|
||||||
filename = obj[filename_field]
|
filename = obj[filename_field]
|
||||||
elif module_resource_path:
|
if not filename and module_resource_path:
|
||||||
filename = os.path.basename(module_resource_path)
|
filename = os.path.basename(module_resource_path)
|
||||||
else:
|
if not filename:
|
||||||
filename = "%s-%s-%s" % (obj._name, obj.id, field)
|
filename = "%s-%s-%s" % (obj._name, obj.id, field)
|
||||||
|
|
||||||
# mimetype
|
# mimetype
|
||||||
@@ -345,6 +345,11 @@ class IrHttp(models.AbstractModel):
|
|||||||
if not mimetype:
|
if not mimetype:
|
||||||
mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype)
|
mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype)
|
||||||
|
|
||||||
|
# extension
|
||||||
|
extension = mimetypes.guess_extension(mimetype)
|
||||||
|
if extension and not filename.endswith(extension):
|
||||||
|
filename = "%s%s" % (filename, extension)
|
||||||
|
|
||||||
headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')]
|
headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')]
|
||||||
|
|
||||||
# cache
|
# cache
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ class MigrationManager(object):
|
|||||||
Python file names must start by `pre-` or `post-` and will be executed, respectively,
|
Python file names must start by `pre-` or `post-` and will be executed, respectively,
|
||||||
before and after the module initialisation. `end-` scripts are run after all modules have
|
before and after the module initialisation. `end-` scripts are run after all modules have
|
||||||
been updated.
|
been updated.
|
||||||
|
A special folder named `0.0.0` can contain scripts that will be run on any version change.
|
||||||
|
In `pre` stage, `0.0.0` scripts are run first, while in `post` and `end`, they are run last.
|
||||||
Example:
|
Example:
|
||||||
<moduledir>
|
<moduledir>
|
||||||
`-- migrations
|
`-- migrations
|
||||||
@@ -71,6 +73,8 @@ class MigrationManager(object):
|
|||||||
|-- 9.0.1.1 # processed only on a 9.0 server
|
|-- 9.0.1.1 # processed only on a 9.0 server
|
||||||
| |-- pre-delete_table_z.py
|
| |-- pre-delete_table_z.py
|
||||||
| `-- post-clean-data.py
|
| `-- post-clean-data.py
|
||||||
|
|-- 0.0.0
|
||||||
|
| `-- end-invariants.py # processed on all version update
|
||||||
`-- foo.py # not processed
|
`-- foo.py # not processed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -117,13 +121,20 @@ class MigrationManager(object):
|
|||||||
return version # the version number already containt the server version
|
return version # the version number already containt the server version
|
||||||
return "%s.%s" % (release.major_version, version)
|
return "%s.%s" % (release.major_version, version)
|
||||||
|
|
||||||
def _get_migration_versions(pkg):
|
def _get_migration_versions(pkg, stage):
|
||||||
versions = sorted({
|
versions = sorted({
|
||||||
ver
|
ver
|
||||||
for lv in self.migrations[pkg.name].values()
|
for lv in self.migrations[pkg.name].values()
|
||||||
for ver, lf in lv.items()
|
for ver, lf in lv.items()
|
||||||
if lf
|
if lf
|
||||||
}, key=lambda k: parse_version(convert_version(k)))
|
}, key=lambda k: parse_version(convert_version(k)))
|
||||||
|
if "0.0.0" in versions:
|
||||||
|
# reorder versions
|
||||||
|
versions.remove("0.0.0")
|
||||||
|
if stage == "pre":
|
||||||
|
versions.insert(0, "0.0.0")
|
||||||
|
else:
|
||||||
|
versions.append("0.0.0")
|
||||||
return versions
|
return versions
|
||||||
|
|
||||||
def _get_migration_files(pkg, version, stage):
|
def _get_migration_files(pkg, version, stage):
|
||||||
@@ -150,10 +161,11 @@ class MigrationManager(object):
|
|||||||
parsed_installed_version = parse_version(installed_version)
|
parsed_installed_version = parse_version(installed_version)
|
||||||
current_version = parse_version(convert_version(pkg.data['version']))
|
current_version = parse_version(convert_version(pkg.data['version']))
|
||||||
|
|
||||||
versions = _get_migration_versions(pkg)
|
versions = _get_migration_versions(pkg, stage)
|
||||||
|
|
||||||
for version in versions:
|
for version in versions:
|
||||||
if parsed_installed_version < parse_version(convert_version(version)) <= current_version:
|
if ((version == "0.0.0" and parsed_installed_version < current_version)
|
||||||
|
or parsed_installed_version < parse_version(convert_version(version)) <= current_version):
|
||||||
|
|
||||||
strfmt = {'addon': pkg.name,
|
strfmt = {'addon': pkg.name,
|
||||||
'stage': stage,
|
'stage': stage,
|
||||||
|
|||||||
Reference in New Issue
Block a user