diff --git a/.gitignore b/.gitignore
index 68bc17f..9c283fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,36 +1,28 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
-*$py.class
+/.venv
+/.pytest_cache
# C extensions
*.so
# Distribution / packaging
.Python
+env/
+bin/
build/
develop-eggs/
dist/
-downloads/
eggs/
-.eggs/
-lib/
lib64/
parts/
sdist/
var/
-wheels/
-share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
-MANIFEST
-
-# PyInstaller
-# Usually these files are written by a python script from a template
-# before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
+*.eggs
# Installer logs
pip-log.txt
@@ -39,122 +31,44 @@ pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
-.nox/
.coverage
-.coverage.*
.cache
nosetests.xml
coverage.xml
-*.cover
-*.py,cover
-.hypothesis/
-.pytest_cache/
-cover/
# Translations
*.mo
-*.pot
+
+# Pycharm
+.idea
+
+# Eclipse
+.settings
+
+# Visual Studio cache/options directory
+.vs/
+.vscode
+
+# OSX Files
+.DS_Store
# Django stuff:
*.log
-local_settings.py
-db.sqlite3
-db.sqlite3-journal
-# Flask stuff:
-instance/
-.webassets-cache
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
-# Scrapy stuff:
-.scrapy
+# Rope
+.ropeproject
# Sphinx documentation
docs/_build/
-# PyBuilder
-.pybuilder/
-target/
+# Backup files
+*~
+*.swp
-# Jupyter Notebook
-.ipynb_checkpoints
-
-# IPython
-profile_default/
-ipython_config.py
-
-# pyenv
-# For a library or package, you might want to ignore these files since the code is
-# intended to run in multiple environments; otherwise, check them in:
-# .python-version
-
-# pipenv
-# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
-# However, in case of collaboration, if having platform-specific dependencies or dependencies
-# having no cross-platform support, pipenv may install dependencies that don't work, or not
-# install all needed dependencies.
-#Pipfile.lock
-
-# poetry
-# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
-# This is especially recommended for binary packages to ensure reproducibility, and is more
-# commonly ignored for libraries.
-# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
-#poetry.lock
-
-# pdm
-# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
-#pdm.lock
-# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
-# in version control.
-# https://pdm.fming.dev/#use-with-ide
-.pdm.toml
-
-# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
-__pypackages__/
-
-# Celery stuff
-celerybeat-schedule
-celerybeat.pid
-
-# SageMath parsed files
-*.sage.py
-
-# Environments
-.env
-.venv
-env/
-venv/
-ENV/
-env.bak/
-venv.bak/
-
-# Spyder project settings
-.spyderproject
-.spyproject
-
-# Rope project settings
-.ropeproject
-
-# mkdocs documentation
-/site
-
-# mypy
-.mypy_cache/
-.dmypy.json
-dmypy.json
-
-# Pyre type checker
-.pyre/
-
-# pytype static type analyzer
-.pytype/
-
-# Cython debug symbols
-cython_debug/
-
-# PyCharm
-# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
-# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
-# and can be added to the global gitignore or merged into this file. For a more nuclear
-# option (not recommended) you can uncomment the following to ignore the entire idea folder.
-#.idea/
+# OCA rules
+!static/lib/
diff --git a/bemade_fsm/__manifest__.py b/bemade_fsm/__manifest__.py
index 0a0e459..a3069fe 100644
--- a/bemade_fsm/__manifest__.py
+++ b/bemade_fsm/__manifest__.py
@@ -35,6 +35,7 @@
'industry_fsm',
'industry_fsm_sale',
'bemade_partner_root_ancestor',
+ 'mail',
],
'data': ['views/task_template_views.xml',
'views/equipment.xml',
@@ -43,11 +44,12 @@
'views/res_partner.xml',
'views/menus.xml',
'views/task_views.xml',
+ 'views/sale_order_views.xml',
],
'assets': {
'web.assets_tests': [
'bemade_fsm/static/tests/tours/task_template_tour.js',
- 'bemade_fsm/static/tests/tours/task_equipment_tour.js',
+ 'bemade_fsm/static/tests/tours/equipment_tour.js',
],
},
'installable': True,
diff --git a/bemade_fsm/models/equipment.py b/bemade_fsm/models/equipment.py
index b82c143..2cbb096 100644
--- a/bemade_fsm/models/equipment.py
+++ b/bemade_fsm/models/equipment.py
@@ -20,6 +20,7 @@ class EquipmentType(models.Model):
name = fields.Char(string='Intervention Name', required=True, translate=True)
+
class Equipment(models.Model):
_name = 'bemade_fsm.equipment'
_rec_name = 'complete_name'
@@ -39,13 +40,16 @@ class Equipment(models.Model):
"Waste water, Pure water")
partner_id = fields.Many2one('res.partner',
string="Owner",
- compute="_compute_partner")
+ compute="_compute_partner",
+ search="_search_partner",)
+
description = fields.Text(string="Description",
tracking=True)
partner_location_id = fields.Many2one('res.partner',
string="Physical Address",
- tracking=True,)
+ tracking=True,
+ ondelete='cascade')
location_notes = fields.Text(string="Physical Location Notes",
tracking=True)
@@ -58,6 +62,10 @@ class Equipment(models.Model):
for rec in self:
rec.partner_id = rec.partner_location_id and rec.partner_location_id.root_ancestor
+ @api.model
+ def _search_partner(self, operator, value):
+ return [('partner_location_id.root_ancestor', operator, value)]
+
@api.depends('pid_tag', 'name')
def _compute_complete_name(self):
for rec in self:
@@ -87,4 +95,4 @@ class Equipment(models.Model):
'context': self.env.context,
'res_model': 'bemade_fsm.equipment',
'type': 'ir.actions.act_window',
- }
\ No newline at end of file
+ }
diff --git a/bemade_fsm/models/res_partner.py b/bemade_fsm/models/res_partner.py
index c9f1877..f5dba22 100644
--- a/bemade_fsm/models/res_partner.py
+++ b/bemade_fsm/models/res_partner.py
@@ -16,7 +16,8 @@ class Partner(models.Model):
string='Site Equipment')
is_site_contact = fields.Boolean(string='Is a site contact',
- compute="_compute_is_site_contact")
+ compute="_compute_is_site_contact",
+ search="_search_is_site_contact",)
site_ids = fields.Many2many(string='Work Sites',
comodel_name='res.partner',
@@ -33,6 +34,14 @@ class Partner(models.Model):
domain=[('is_company', '=', False)],
tracking=True)
+ work_order_contacts = fields.Many2many(string='Work Order Recipients',
+ comodel_name='res.partner',
+ relation='res_partner_work_order_contacts_rel',
+ column1='res_partner_id',
+ column2='work_order_contact_id',
+ domain=[('is_company', '=', False)],
+ tracking=True)
+
@api.depends('site_ids')
def _compute_is_site_contact(self):
for rec in self:
@@ -41,5 +50,9 @@ class Partner(models.Model):
@api.depends('equipment_ids')
def _compute_equipment_count(self):
for rec in self:
- all_equipmemt_ids = self.env['bemade_fsm.equipment'].search([('partner_id', '=', rec.id)])
- rec.equipment_count = len(all_equipmemt_ids)
+ all_equipment_ids = self.env['bemade_fsm.equipment'].search([('partner_id', '=', rec.id)])
+ rec.equipment_count = len(all_equipment_ids)
+
+ @api.model
+ def _search_is_site_contact(self, operator, value):
+ return [('site_contacts', '!=', False)]
diff --git a/bemade_fsm/models/sale_order.py b/bemade_fsm/models/sale_order.py
index 0605e28..d0842b6 100644
--- a/bemade_fsm/models/sale_order.py
+++ b/bemade_fsm/models/sale_order.py
@@ -1,6 +1,49 @@
from odoo import fields, models, api, _, Command
+class SaleOrder(models.Model):
+ _inherit = 'sale.order'
+
+ site_contacts = fields.Many2many(comodel_name='res.partner',
+ relation="sale_order_site_contacts_rel",
+ compute="_compute_default_contacts",
+ inverse="_inverse_default_contacts",
+ string='Site Contacts',
+ store=True)
+
+ work_order_contacts = fields.Many2many(comodel_name='res.partner',
+ relation='sale_order_work_order_contacts_rel',
+ compute='_compute_default_contacts',
+ inverse='_inverse_default_contacts',
+ string='Work Order Recipients',
+ store=True)
+
+ equipment_ids = fields.Many2many(comodel_name='bemade_fsm.equipment',
+ compute='_compute_equipment',
+ inverse='_inverse_equipment',
+ string='Equipment to Service',
+ store=True,
+ ondelete='restrict')
+
+ @api.depends('partner_id')
+ def _compute_default_contacts(self):
+ for rec in self:
+ rec.site_contacts = rec.partner_shipping_id.site_contacts
+ rec.work_order_contacts = rec.partner_shipping_id.work_order_contacts
+
+ def _inverse_default_contacts(self):
+ pass
+
+ @api.depends('partner_id')
+ def _compute_equipment(self):
+ for rec in self:
+ rec.equipment_ids = self.partner_shipping_id.equipment_ids if len(
+ self.partner_shipping_id.equipment_ids) <= 1 else False
+
+ def _inverse_equipment(self):
+ pass
+
+
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
diff --git a/bemade_fsm/models/task_template.py b/bemade_fsm/models/task_template.py
index f95b3c7..3f70518 100644
--- a/bemade_fsm/models/task_template.py
+++ b/bemade_fsm/models/task_template.py
@@ -3,7 +3,7 @@ from odoo import models, fields, api, _
class TaskTemplate(models.Model):
_name = 'project.task.template'
-
+ _description = "Template for new project tasks"
@api.model
def _current_company(self):
return self.env.company
diff --git a/bemade_fsm/static/tests/tours/equipment_tour.js b/bemade_fsm/static/tests/tours/equipment_tour.js
new file mode 100644
index 0000000..8a6bf49
--- /dev/null
+++ b/bemade_fsm/static/tests/tours/equipment_tour.js
@@ -0,0 +1,126 @@
+/** @odoo-module **/
+
+import tour from 'web_tour.tour';
+
+const TEST_COMPANY = "Test Partner Company";
+const TEST_EQPT1 = "Test Equipment 1";
+const TEST_EQPT2 = "Test Equipment 2";
+tour.register('equipment_base_tour', {
+ test: true,
+ url: '/web',
+ }, /* Create a new "Test Equipment" and link it to "Test Partner Company" */
+ [tour.stepUtils.showAppsMenuItem(), {
+ content: 'Navigate to the Service menu',
+ trigger: '.o_app[data-menu-xmlid="industry_fsm.fsm_menu_root"]',
+ }, {
+ content: 'Navigate to the Clients submenu',
+ trigger: 'button.dropdown-toggle[data-menu-xmlid="bemade_fsm.menu_service_client"]',
+ }, {
+ content: 'Navigate to the Equipment menu',
+ trigger: '.dropdown-item[data-menu-xmlid="bemade_fsm.menu_service_client_equipment"]',
+ }, {
+ content: 'Click the create button',
+ trigger: '.o_list_button_add',
+ extra_trigger: 'li.breadcrumb-item.active:has(span:contains(Equipment))',
+ }, {
+ content: 'Add a tag',
+ trigger: 'input[name="pid_tag"]',
+ run: 'text TestPIDTag',
+ }, {
+ content: 'Set the name',
+ trigger: 'input[name="name"]',
+ run: `text ${TEST_EQPT2}`,
+ }, {
+ content: 'Set the partner',
+ trigger: 'div[name="partner_location_id"] div div input',
+ run: 'text Test Partner Company',
+ }, {
+ content: 'Click the partner in the dropdown',
+ trigger: `li a.dropdown-item:contains(${TEST_COMPANY})`,
+ }, {
+ content: 'Save equipment',
+ trigger: 'button.o_form_button_save',
+ }, {
+ /* Navigate to the client and make sure that there are two equipments saved (one from the Python test case) */
+ content: 'Navigate to the Clients submenu',
+ trigger: 'button.dropdown-toggle[data-menu-xmlid="bemade_fsm.menu_service_client"]',
+ }, {
+ content: 'Click on the clients submenu',
+ trigger: '.dropdown-item[data-menu-xmlid="bemade_fsm.menu_service_client_clients"]',
+ }, {
+ content: 'Search for the Test Partner Company',
+ trigger: 'input.o_searchview_input',
+ extra_trigger: 'li.breadcrumb-item.active:has(span:contains(Customers))',
+ run: `text ${TEST_COMPANY}`
+ }, {
+ content: 'Validate Search',
+ trigger: '.o_menu_item.o_selection_focus',
+ run: 'click',
+ }, {
+ content: 'Open the test client.',
+ trigger: `div.o_kanban_record:has(span:contains(${TEST_COMPANY}))`,
+ }, {
+ content: 'Click the Field Service tab.',
+ trigger: 'a.nav-link:contains(Field Service)',
+ extra_trigger: `h1 span.o_field_partner_autocomplete[name="name"]:contains(${TEST_COMPANY})`,
+ }, {
+ content: 'Make sure we have a first test equipment',
+ /*trigger: `div[name="equipment_ids"]:has(td:contains(${TEST_EQPT1}))`,*/
+ trigger: `td:contains(${TEST_EQPT1})`,
+ run: function () {
+ },
+ }, {
+ content: 'Make sure we have a second test equipment',
+ trigger: `div[name="equipment_ids"]:has(td:contains(${TEST_EQPT2}))`,
+ run: function () {
+ },
+ }
+ ]);
+
+tour.register('equipment_sale_order_tour', {
+ test: true,
+ url: '/web',
+}, [tour.stepUtils.showAppsMenuItem(), {
+ content: 'Navigate to the Sales menu',
+ trigger: '.o_app[data-menu-xmlid="sale.sale_menu_root"]',
+}, {
+ content: 'Create an order',
+ trigger: 'button.o_list_button_add',
+}, {
+ content: 'Select the test partner',
+ trigger: 'div[name="partner_id"] input',
+ run: `text ${TEST_COMPANY}`,
+}, {
+ content: 'Click the partner in the dropdown',
+ trigger: `li a.dropdown-item:contains(${TEST_COMPANY})`,
+}, {
+ content: 'Save',
+ trigger: 'button.o_form_button_save',
+}, {
+ content: 'Navigate to the Field Service tab.',
+ trigger: 'a.nav-link[role="tab"]:contains(Field Service)'
+}, {
+ content: 'Check that default equipment shows up.',
+ trigger: `.o_field_cell:contains(${TEST_EQPT1})`,
+}, {
+ content: 'Add test equipment 2',
+ trigger: `div[name="equipment_ids"] a:contains(Add a line)`,
+}, {
+ content: 'Click create',
+ trigger: '.modal-footer > button:has(span:contains(Create))',
+}, {
+ content: 'Name the new equipment',
+ trigger: 'input.o_field_widget[name="name"]',
+ run: `text ${TEST_EQPT2}`,
+}, {
+ content: 'Save & Close',
+ trigger: 'button:has(span:contains(Save & Close))',
+}, {
+ content: 'Save',
+ trigger: 'button.o_form_button_save',
+}, {
+ content: 'Check that the new equipment was added',
+ trigger: `.o_field_cell:contains(${TEST_EQPT2})`,
+ run: function () {},
+}
+]);
\ No newline at end of file
diff --git a/bemade_fsm/tests/__init__.py b/bemade_fsm/tests/__init__.py
index a66b934..fc3738e 100644
--- a/bemade_fsm/tests/__init__.py
+++ b/bemade_fsm/tests/__init__.py
@@ -2,3 +2,4 @@ from . import test_bemade_fsm_common
from . import test_task_template
from . import test_task_template_sale_order
from . import test_equipment
+from . import test_fsm_contact_setting
diff --git a/bemade_fsm/tests/test_bemade_fsm_common.py b/bemade_fsm/tests/test_bemade_fsm_common.py
index 47942ac..4fcfe35 100644
--- a/bemade_fsm/tests/test_bemade_fsm_common.py
+++ b/bemade_fsm/tests/test_bemade_fsm_common.py
@@ -1,6 +1,8 @@
-from odoo.tests.common import TransactionCase
+from odoo.tests.common import TransactionCase, tagged
from odoo import Command
+
+@tagged("-at_install", "post_install")
class FSMManagerUserTransactionCase(TransactionCase):
@classmethod
diff --git a/bemade_fsm/tests/test_equipment.py b/bemade_fsm/tests/test_equipment.py
index 2ca0485..c2d4b8d 100644
--- a/bemade_fsm/tests/test_equipment.py
+++ b/bemade_fsm/tests/test_equipment.py
@@ -1,6 +1,10 @@
from odoo.tests.common import HttpCase, tagged
from .test_bemade_fsm_common import FSMManagerUserTransactionCase
+from odoo import Command
+from odoo.exceptions import MissingError
+
+@tagged("-at_install", "post_install")
class TestEquipmentCommon(FSMManagerUserTransactionCase):
@classmethod
@@ -13,8 +17,8 @@ class TestEquipmentCommon(FSMManagerUserTransactionCase):
'company_type': 'company',
'street': '123 Street St.',
'city': 'Montreal',
- 'state_id': cls.env['res.country.state'].search([('name','ilike','Quebec%')]).id,
- 'country_id': cls.env['res.country'].search([('name','=','Canada')]).id
+ 'state_id': cls.env['res.country.state'].search([('name', 'ilike', 'Quebec%')]).id,
+ 'country_id': cls.env['res.country'].search([('name', '=', 'Canada')]).id
})
cls.partner_contact = cls.env['res.partner'].create({
@@ -30,8 +34,26 @@ class TestEquipmentCommon(FSMManagerUserTransactionCase):
@tagged('-at_install', 'post_install')
-class TestEquipmentTour(HttpCase, TestEquipmentCommon):
+class TestEquipmentBase(TestEquipmentCommon):
- def test_equipment_tour(self):
- self.start_tour('/web', 'task_equipment_tour',
+ def test_crd(self):
+ # Just make sure the basic ORM stuff is OK
+ self.assertTrue(self.equipment in self.partner_company.equipment_ids)
+ self.assertTrue(len(self.partner_company.equipment_ids) == 1)
+ self.partner_company.write({'equipment_ids': [Command.set([])]})
+ # Delete should cascade
+ with self.assertRaises(MissingError):
+ self.equipment.name
+
+
+@tagged('-at_install', 'post_install')
+class TestEquipmentTours(HttpCase, TestEquipmentCommon):
+
+ def test_equipment_base_tour(self):
+ self.start_tour('/web', 'equipment_base_tour',
login=self.user.login, )
+
+ def test_equipment_sale_order_tour(self):
+ self.start_tour('/web', 'equipment_sale_order_tour', login=self.user.login)
+ # Make sure the equipment added to the SO in the test tour was added to the partner
+ self.assertEqual(len(self.partner_company.equipment_ids), 2)
diff --git a/bemade_fsm/tests/test_fsm_contact_setting.py b/bemade_fsm/tests/test_fsm_contact_setting.py
index a8874c2..7d32ecb 100644
--- a/bemade_fsm/tests/test_fsm_contact_setting.py
+++ b/bemade_fsm/tests/test_fsm_contact_setting.py
@@ -1,30 +1,56 @@
from odoo.tests import TransactionCase, HttpCase, tagged
from odoo import Command
-from test_bemade_fsm_common import FSMManagerUserTransactionCase
+from .test_bemade_fsm_common import FSMManagerUserTransactionCase
+
+@tagged("-at_install", "post_install")
class SaleOrderFSMContactsCase(FSMManagerUserTransactionCase):
- def test_default_site_contacts(self):
- # Make sure the SO pulls the defaults from the partner correctly
- pass
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ Partner = cls.env['res.partner']
+ cls.parent_co = Partner.create({
+ 'name': 'Parent Co',
+ 'company_type': 'company',
+ })
+ cls.contact_1 = Partner.create({
+ 'name': 'Contact 1',
+ 'company_type': 'person',
+ 'parent_id': cls.parent_co.id,
+ })
+ cls.contact_2 = Partner.create({
+ 'name': 'Contact 2',
+ 'company_type': 'person',
+ 'parent_id': cls.parent_co.id,
+ })
- def test_default_billing_contacts(self):
+ def test_site_contacts(self):
# Make sure the SO pulls the defaults from the partner correctly
- pass
+ self.parent_co.write({'site_contacts': [Command.set([self.contact_1.id, self.contact_2.id])]})
+ so = self.env['sale.order'].create({
+ 'partner_id': self.parent_co.id,
+ })
+ self.assertTrue(so.site_contacts == self.parent_co.site_contacts)
+ # Make sure updating the site contacts on the SO doesn't feed back to the partner
+ so.write({'site_contacts': [Command.set([self.contact_1.id])]})
+ self.assertTrue(self.contact_1 in so.site_contacts)
+ self.assertTrue(self.contact_2 not in so.site_contacts)
+ self.assertTrue(so.site_contacts != so.partner_id.site_contacts and len(so.partner_id.site_contacts) == 2)
def test_default_workorder_contacts(self):
# Make sure the SO pulls the defaults from the partner correctly
- pass
-
- def test_change_site_contacts(self):
- # Make sure the SO contacts can be updated without feeding back to the partner
- pass
-
- def test_change_workorder_contacts(self):
- # Make sure the SO contacts can be updated without feeding back to the partner
- pass
-
- def test_change_billing_contacts(self):
- # Make sure the SO contacts can be updated without feedin back to the partner
- pass
-
+ self.parent_co.write({'work_order_contacts': [Command.set([self.contact_1.id, self.contact_2.id])]})
+ so = self.env['sale.order'].create({
+ 'partner_id': self.parent_co.id,
+ })
+ self.assertTrue(self.contact_1 in self.parent_co.work_order_contacts)
+ self.assertTrue(self.contact_2 in self.parent_co.work_order_contacts)
+ self.assertTrue(self.contact_1 in so.work_order_contacts)
+ self.assertTrue(self.contact_2 in so.work_order_contacts)
+ # Make sure setting the work order contacts on the SO doesn't feed back to the partner
+ so.write({'work_order_contacts': [Command.set([self.contact_1.id])]})
+ self.assertTrue(self.contact_1 in so.work_order_contacts)
+ self.assertTrue(self.contact_2 not in so.work_order_contacts)
+ self.assertTrue(
+ so.work_order_contacts != so.partner_id.work_order_contacts and len(so.partner_id.work_order_contacts) == 2)
diff --git a/bemade_fsm/tests/test_task_template.py b/bemade_fsm/tests/test_task_template.py
index bd46e0a..c0bce51 100644
--- a/bemade_fsm/tests/test_task_template.py
+++ b/bemade_fsm/tests/test_task_template.py
@@ -5,6 +5,7 @@ from odoo import Command
from psycopg2.errors import ForeignKeyViolation
+@tagged("-at_install", "post_install")
class TestTaskTemplateCommon(FSMManagerUserTransactionCase):
@classmethod
diff --git a/bemade_fsm/tests/test_task_template_sale_order.py b/bemade_fsm/tests/test_task_template_sale_order.py
index 176c222..e2fe05e 100644
--- a/bemade_fsm/tests/test_task_template_sale_order.py
+++ b/bemade_fsm/tests/test_task_template_sale_order.py
@@ -2,6 +2,7 @@ from .test_task_template import TestTaskTemplateCommon
from odoo.tests.common import tagged
+@tagged("-at_install", "post_install")
class TestTaskTemplateSalesOrder(TestTaskTemplateCommon):
@classmethod
def setUpClass(cls):
diff --git a/bemade_fsm/views/res_partner.xml b/bemade_fsm/views/res_partner.xml
index d451cb9..1cd4cf8 100644
--- a/bemade_fsm/views/res_partner.xml
+++ b/bemade_fsm/views/res_partner.xml
@@ -25,10 +25,18 @@
+
+
+
+
+
+
+
+
-
+