<h1>Odoo Academy</h1>
<h4>Criação do Módulo Odoo Academy</h4>
<p>A aplicação tera funcionalidades como a criação de cursos, alocação de aulas dentro desses cursos, estas que terão alunos e professores associados,terão data de inicio e término, vagas disponíveis e duração.</p>
<h5>Estrutura básica do módulo:</h5>
<p><code>bash
├── __init__.py
├── __openerp__.py
├── models
│ ├── __init__.py
│ ├── courses.py
│ ├── partners.py
│ └── session.py
└── views
├── courses_view.xml
├── partners_view.xml
└── session_view.xml
</code>
<code>__init__.py</code>: Este arquivo permite transformar a pasta em que esta alocado em módulo(estrutura que irá agrupar os arquivos presentes, facilitando na imporatação)</p>
<p>```python</p>
<h1>Arquivo <strong>init</strong> localizado em models</h1>
<p>from . import courses
from . import partners
from . import session
```</p>
<p><code>__openerp__.py</code>: Este arquivo permite funciona como manifesto do módulo, nele estão informações sobre a aplicação e especificações de dependências e views.</p>
<p><code>python
{
'name': 'Nome Módulo'
'version': 'Versão Módulo'
'summary': 'Sumário Módulo'
'description': 'Descrição'
'category': 'Categoria'
'author': 'Autor da Aplicação'
'website': 'Website'
'license': 'licença(AGPL-3)'
'depends':['dependencia.modulo1', 'dependencia.modulo12]
'data':['views/view1_view1.xml',
'views/view1_view2.xml],
}
</code></p>
<h4>Criação das Models Session, Courses e Partners</h4>
<p>-Dentro das models serão especificados os campos a serem exibidos nas views, especificação de dependencias nesses campos, os comportamentos/métodos executados, bem como seus gatilhos.</p>
<h5>Modelo básico de uma model:</h5>
<p>```python
from openerp import fields, models, api</p>
<p>Class Model1(models.Model):</p>
<pre><code>_name = 'modulo.nomeclasse'
abool = fields.Boolean()
achar = fields.Char()
atext = fields.Text()
anhtml = fields.Html()
anint = fields.Integer()
afloat = fields.Float()
adate = fields.Date()
abin = fields.Binary()
aselection = fields.Selection([('valorASerGuardado1', 'TextoExibido1'),('valorASerGuardado2', 'TextoExibido2')])
//Geralmente o campo abaixo fica em outra model, levando em consideração que se queira fazer relação entre models
arel_id = fields.Many2one(comodel_name='res_partner')
//O atributo 'rel_id' trata-se do campo Many2one a qual se quer relacionar
arel_ids = fields.One2many(comodel_name='res_partner', inverse_name = 'rel_id')
//O método abaixo é acionado quando há mudanças em achar
@api.onchange(achar)
def _faz_alguma_coisa(self)
...
pass
def _faz_outra_coisa(self)
...
pass
</code></pre>
<p>```
Os campos mostrados acima são opções que podem ser implementadas nos formulários que serão montados. dentro desses campos há diversas opções de <strong>atributos</strong>, que podem customizar sua aparência ou relaciona-los a gatilhos(openerp.api). </p>
<p><code>python
name = fields.Char(
string="Name",
compute="_compute_name_custom",
store=True,
select=True,
readonly=True,
inverse="_write_name"
required=True,
translate=True,
help='blabla',
company_dependent=True,
search='_search_function'
)
</code>
Abaixo á uma lista dos que podem ser implementados.</p>
<p><strong><em>string</em></strong>: string de exibição do campo.<br>
<strong><em>compute</em></strong>: transforma o campo em questão em um campo computed, o associando a uma função que determinará seu valor dinamicamente.<br>
<strong><em>store</em></strong>: Utilizado juntamente com o atributo <em>compute</em>, tem valor booleano, quando <em>True</em>, salva o campo na tabela da model em questão.
<strong><em>select</em></strong>: Força um index no campo.<br>
<strong><em>readonly</em></strong>: o campo não poderá ser alterado.<br>
<strong><em>inverse</em></strong>: funciona como um gatilho, associa-se esse atributo a uma função, que será chamada sempre que houver atualizações.<br>
<strong><em>required</em></strong>: torna o campo obrigatório, caso True.<br>
<strong><em>translate</em></strong>: Ativa o Tranlation(tradutor).<br>
<strong><em>help</em></strong>: cria um <em>help</em> para o campo, uma espécie de breve descrição.<br>
<strong><em>search</em></strong>: atribui uma função de pesquisa customizada, geralmente utilizada em conjunto com o atributo <em>compute</em>.<br>
<strong><em>company_dependent</em></strong>: Transforma o campo dependente a compania de registro, usuários cadastrados em diferentes companias, poderão ver valores diferentes para a mesma coluna.<br>
<strong><em>default</em></strong>: Define um valor padrão para o campo.<br>
<strong><em>related</em></strong>: torna o campo diretamente relacionado a alterações em outra model.<br></p>
<h4>Criação das Views de Session, Courses e Partners</h4>
<p>-Dentro das views serão alocados os campos criados nas models, e por meio de tags, customizar sua exibição/posicionamento.</p>
<h5>Estrutura básica de uma view</h5>
<p>```xml
<openerp>
<data></p>
<pre><code> <!--O menu abaixo será exibido na barra superior-->
<menuitem id="id_novomenu" name="Nome Módulo" sequence="450"/>
<!--O atributo model classifica o tipo -->
<!--de record criado, no caso abaixo ir.ui.view,-->
<!--utilizado para views que exibirão estruturas-->
<!--como form, tree, kanban, graph dentre outros-->
<record model="ir.ui.view" id="view_nomemodulo_nomemodel_form">
<field name="name">Nome Record</field>
<field name="model">Nome da Model</field>
<field name="arch" type="xml">
<!--Neste espaço colocamos os campos criados-->
<!--na model, e escolhemos o tipo de exibição-->
<!--(tag de kanban, tree, form e etc), há-->
<!--limitações de campos e atributos dependendo-->
<!--do tipo de exibição escolhido, neste caso-->
<!--exibiremos o tipo form(Exibira Formulario-->
<form>
<!--A tag 'header' agrupa elementos no CABEÇALHO do formulário-->
<header>
<!--O 'widget' statusbar transforma o campo do tipo select em uma status bar(também há um widget que o exibe em formato radio)-->
<field name="aselection" widget="statusbar"/>
</header>
<!--A tag 'sheet' agrupa elementos no CORPO do formulário-->
<sheet>
<!--A tag 'group' agrupa os campos-->
<group>
<field name="abool"/>
<field name="achar"/>
<field name="atext"/>
<field name="anint"/>
</group>
<button string="Faz Algo" type="object" name="_faz_outra_coisa"/>
<!--A tag notebook cria exibição em abas, que são identificadas pela tag 'page'-->
<notebook>
<page string="String Pagina">
<field name="arel_ids"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="view_nomemodulo_nomemodel_tree">
<field name="name">Nome Record</field>
<field name="model">Nome da Model</field>
<field name="arch" type="xml">
<!--O tag tree, especificada abaixo, determina-->
<!--que o record em questão, exibira os campos em-->
<!--formato de lista-->
<tree string="Session">
<field name="achar"/>
<field name="aint"/>
</tree>
</field>
</record>
<!--Os menus abaixo serão exibidos na barra lateral-->
<menuitem id="id_submenu" name="Titulo Menu"
parent="id_novomenu" sequence="1"/>
<!--O atributo 'action' chama o record com o id especificado-->
<menuitem id="submenu_model1" name="Model1"
parent="id_submenu"
action="action_modulo_model" sequence="1"/>
<record id="action_nomemodulo_nomemodel" model="ir.actions.act_window">
<field name="name">Nome Record</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">Nome da Model</field>
<field name="view_mode">tree,form</field>
</record>
</data>
</code></pre>
<p></openerp>
```</p>
<h2>Módulo Locadora</h2>
<p>Construa as models Categoria, Filme, OperacaoUnit, OperacaoConj e Cliente</p>
<ul>
<li><strong>Cliente:</strong>
<ul>
<li>filme_ids - many2many</li>
<li>operacaoconj_ids - one2many</li>
<li>valor_gasto - float(será um campo <em>compute</em>)</li>
</ul></li>
<li><strong>Categoria:</strong>
<ul>
<li>nome - char</li>
<li>filme_ids - many2many</li>
</ul></li>
<li><strong>Filme:</strong>
<ul>
<li>titulo - char</li>
<li>categoria_ids - many2many</li>
<li>valor - float</li>
<li>descrição - text</li>
<li>data - date</li>
<li>quantidade - int</li>
<li>autor - char</li>
</ul></li>
<li><strong>OperacaoUnit:</strong>
<ul>
<li>operacaounit_id - many2one</li>
<li>tipo - select [venda, aluguel]</li>
<li>preco - float(será um campo <em>compute</em>)</li>
<li>filme_ids - many2many</li>
<li>status - select <a href="ser%C3%A1%20um%20campo%20*compute*">indisponível, em espera, disponível, atrasado</a></li>
<li>dataOperacao - date</li>
<li>dataEntrega - date(o campo em questão só fica aberto a escrita quando tipo(OperacaoUnit) é aluguel)</li>
</ul></li>
<li><strong>OperacaoConj:</strong>
<ul>
<li>operacaounit_ids - one2many</li>
<li>cliente_id - many2one</li>
<li>valor - float(será um campo <em>compute</em>)</li>
</ul></li>
</ul>
<h5>Observações sobre alguns campos:</h5>
<p>-O campo valor em OperacaoConj deve ser a soma de todos os preços definidos em instancias associadas de OperacaoUnit, será necessário utilizar o módulo api, mais especificamente o decorator api.depends(*mais detalhes sobre os decorator de api na <a href="https://www.odoo.com/documentation/8.0/reference/orm.html#module-openerp.api">documentação</a></p>
<p>-O campo valor_gasto em Cliente deve ser a soma de todos os valores definidos em instancias associadas de OperacaoConj</p>
<p>-Assim como foi dito acima, o campo preco(OperacaoUnit) é dependente direto de tipo(OperacaoUnit), dataEntrega(OperacaoUnit), e data(Filme), será necessário utilizar o módulo api, mais especificamente o decorator api.depends(<em>mais detalhes sobre os decorator de api na <a href="https://www.odoo.com/documentation/8.0/reference/orm.html#module-openerp.api">documentação</a></em>)</p>
<p><em>Para mais detalhes de como manusear campos relacionais (one2many, many2one, many2many, visite a <a href="https://www.odoo.com/documentation/8.0/reference/orm.html#relational-fields">documentação oficial</a>, ou observe um <a href="https://www.odoo.com/documentation/8.0/howtos/backend.html">caso de uso</a> fornecido pelo odoo com exemplos de uso para cada campo relacional).</em></p>
<h4>Detalhes do funcionamento do módulo</h4>
<ul>
<li><p>Ao salvar uma operaçãoUnit com tipo aluguel(alugar um filme), definir o preço como R$4,00 caso for lançamento(com campo data de no maximo 3 meses de diferença da data atual), senão definir preço como R$2,00.</p></li>
<li><p>O prazo de entrega do filme é de 2 dias, caso haja atraso, cobrar juros simples de 50% do valor definido em preço(OperacaoUnit) por dia de atraso.</p></li>
<li><p>Caso a operação seja do tipo venda, cobrar no filme um valor de 30% a mais do seu valor(Filme), e logicamente decrescer a quantidade do estoque.</p></li>
<li><p>Ao criar uma OperacaoUnit o campo dataOperacao recebe a data atual.</p></li>
<li><p>Ao alugar filme, este fica temporariamente fora de estoque, até ser devolvido(decrescido do estoque)</p></li>
<li><p>Campo status deve ser um workflow com as opções que foram descritas na criação da model, os status a seguir terão os seguintes botões para edição de status.</p>
<ul>
<li>Alugar - somente em status 'Disponível'</li>
<li>Vender - somente em status 'Disponível'</li>
<li>Concluir - somente em status 'Em espera' ou 'Atrasado'</li>
</ul></li>
<li><p>A definição do status exibido por OperacaoUnit depende de algumas condições.</p>
<ul>
<li>Indisponível - quando não há cópias do filme em estoque, ou alugadas.</li>
<li>Em espera - quando não há cópias em estoque porém existe cópias alugadas dentro do prazo de entrega, neste caso deve ser exibida a data de entrega da cópia do filme que foi alugada com data de entrega mais proxima da data atual(dentro do campo dataEntrega).</li>
<li>Atrasado - quando não há cópias em estoque porém existem cópias alugadas dentro fora do prazo de entrega, neste caso esse status é exclusivo de OperacaoUnit que ainda estão a ser feitas(que ainda não foram criadas).</li>
<li>Disponível - quando há cópias em estoque, diponíveis para operações(venda ou aluguel)</li>
</ul></li>
</ul>
<p><em>Na documentação oficial há um exemplo de como criar um workflow completo segue o <a href="https://www.odoo.com/documentation/8.0/howtos/backend.html#workflows">link</a>)</em></p>