Merge lp:~camptocamp/contract-management/7.0-block-send-email-lep into lp:~contract-management-core-editors/contract-management/7.0

Proposed by Leonardo Pistone
Status: Merged
Approved by: Yannick Vaucher @ Camptocamp
Approved revision: 10
Merged at revision: 8
Proposed branch: lp:~camptocamp/contract-management/7.0-block-send-email-lep
Merge into: lp:~contract-management-core-editors/contract-management/7.0
Diff against target: 659 lines (+571/-38)
5 files modified
analytic_hours_block/__openerp__.py (+1/-0)
analytic_hours_block/hours_block.py (+41/-0)
analytic_hours_block/hours_block_data.xml (+24/-0)
analytic_hours_block/hours_block_view.xml (+45/-38)
analytic_hours_block/i18n/analytic_hours_block.pot (+460/-0)
To merge this branch: bzr merge lp:~camptocamp/contract-management/7.0-block-send-email-lep
Reviewer Review Type Date Requested Status
Matthieu Dietrich @ camptocamp (community) Approve
Guewen Baconnier @ Camptocamp Approve
Pedro Manuel Baeza Abstain
Review via email: mp+200812@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

Hi, Leonardo, very appreciated the improvement!

Could you please add updated translation template to allow translation of the mail?

Regards.

review: Needs Fixing
9. By Leonardo Pistone

[add] analytic_hours_block: pot file

Revision history for this message
Leonardo Pistone (lepistone) wrote :

Pedro, I added the pot file.

Best

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

l50ff it seems to me that it is dangerous to return a new action with the current context. I encountered subtle bugs because the active_ids, active_model etc are propagated to the new action when they shouldn't. I think it should just be a new dict.

review: Needs Fixing
Revision history for this message
Leonardo Pistone (lepistone) wrote :

Thanks Guewen.

but what about lang, timezone..

Maybe I could pop out the active_* from ctx?

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

The timezone and lang are automatically set from the user. When one click on a menu item, this is also what happens: the context is empty (or as defined in the action) and the user's configuration is set again.

Revision history for this message
Pedro Manuel Baeza (pedro.baeza) wrote :

I can't review this module more than the check of the pot file for now, so I'm going to abstain to not disturb review status.

Regards.

review: Abstain
10. By Leonardo Pistone

[imp] create a new context, as suggested by Guewen

Revision history for this message
Leonardo Pistone (lepistone) wrote :

Good to know Guewen. Done.

Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Thanks! LGTM

review: Approve
Revision history for this message
Matthieu Dietrich @ camptocamp (mdietrich-c2c) wrote :

Hi Leonardo,

LGTM.

Revision history for this message
Matthieu Dietrich @ camptocamp (mdietrich-c2c) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'analytic_hours_block/__openerp__.py'
--- analytic_hours_block/__openerp__.py 2012-12-17 14:42:58 +0000
+++ analytic_hours_block/__openerp__.py 2014-01-31 14:46:22 +0000
@@ -44,6 +44,7 @@
44 ],44 ],
45 "data": [45 "data": [
46 "hours_block_view.xml",46 "hours_block_view.xml",
47 "hours_block_data.xml",
47 "hours_block_menu.xml",48 "hours_block_menu.xml",
48 "report.xml",49 "report.xml",
49 "security/hours_block_security.xml",50 "security/hours_block_security.xml",
5051
=== modified file 'analytic_hours_block/hours_block.py'
--- analytic_hours_block/hours_block.py 2012-12-18 11:05:03 +0000
+++ analytic_hours_block/hours_block.py 2014-01-31 14:46:22 +0000
@@ -24,6 +24,7 @@
2424
25class AccountHoursBlock(orm.Model):25class AccountHoursBlock(orm.Model):
26 _name = "account.hours.block"26 _name = "account.hours.block"
27 _inherit = ['mail.thread']
2728
28 def _get_last_action(self, cr, uid, ids, name, arg, context=None):29 def _get_last_action(self, cr, uid, ids, name, arg, context=None):
29 """ Return the last analytic line date for an invoice"""30 """ Return the last analytic line date for an invoice"""
@@ -163,6 +164,46 @@
163 block_ids.update([inv.id for inv in invoice.account_hours_block_ids])164 block_ids.update([inv.id for inv in invoice.account_hours_block_ids])
164 return list(block_ids)165 return list(block_ids)
165166
167 def action_send_block(self, cr, uid, ids, context=None):
168 """Open a form to send by email. Return an action dict."""
169
170 assert len(ids) == 1, '''\
171 This option should only be used for a single ID at a time.'''
172
173 ir_model_data = self.pool.get('ir.model.data')
174
175 try:
176 template_id = ir_model_data.get_object_reference(
177 cr, uid, 'analytic_hours_block', 'email_template_hours_block'
178 )[1]
179 except ValueError:
180 template_id = False
181
182 try:
183 compose_form_id = ir_model_data.get_object_reference(
184 cr, uid, 'mail', 'email_compose_message_wizard_form'
185 )[1]
186 except ValueError:
187 compose_form_id = False
188
189 ctx = {
190 'default_model': self._name,
191 'default_res_id': ids[0],
192 'default_use_template': bool(template_id),
193 'default_template_id': template_id,
194 'default_composition_mode': 'comment',
195 }
196 return {
197 'type': 'ir.actions.act_window',
198 'view_type': 'form',
199 'view_mode': 'form',
200 'res_model': 'mail.compose.message',
201 'views': [(compose_form_id, 'form')],
202 'view_id': compose_form_id,
203 'target': 'new',
204 'context': ctx,
205 }
206
166 _recompute_triggers = {207 _recompute_triggers = {
167 'account.hours.block': (lambda self, cr, uid, ids, c=None:208 'account.hours.block': (lambda self, cr, uid, ids, c=None:
168 ids, ['invoice_id', 'type'], 10),209 ids, ['invoice_id', 'type'], 10),
169210
=== added file 'analytic_hours_block/hours_block_data.xml'
--- analytic_hours_block/hours_block_data.xml 1970-01-01 00:00:00 +0000
+++ analytic_hours_block/hours_block_data.xml 2014-01-31 14:46:22 +0000
@@ -0,0 +1,24 @@
1<?xml version="1.0" ?>
2<openerp>
3 <!-- Mail template are declared in a NOUPDATE block
4 so users can freely customize/delete them -->
5 <data noupdate="1">
6 <record id="email_template_hours_block" model="email.template">
7 <field name="name">Hours Block - Send by Email</field>
8 <field name="email_from">${(object.user_id.email or object.company_id.email or 'noreply@localhost')|safe}</field>
9 <field name="subject">${object.company_id.name} Hours Block (Ref ${object.number or 'n/a'})</field>
10 <field name="email_recipients">${object.partner_id.id}</field>
11 <field name="model_id" ref="analytic_hours_block.model_account_hours_block"/>
12 <field name="auto_delete" eval="True"/>
13 <field name="report_template" ref="block_hours_report"/>
14 <field name="report_name">Hours_Block_${(object.number or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''}</field>
15 <field name="lang">${object.partner_id.lang}</field>
16 <field name="body_html"><![CDATA[
17 <p>Hello ${object.partner_id.name},</p>
18
19 <p>Please find attached your Hours Block Report.</p>
20 <p>Best regards.</p>
21 ]]></field>
22 </record>
23 </data>
24</openerp>
025
=== modified file 'analytic_hours_block/hours_block_view.xml'
--- analytic_hours_block/hours_block_view.xml 2012-12-18 08:46:36 +0000
+++ analytic_hours_block/hours_block_view.xml 2014-01-31 14:46:22 +0000
@@ -41,44 +41,51 @@
41 <field name="model">account.hours.block</field>41 <field name="model">account.hours.block</field>
42 <field name="arch" type="xml">42 <field name="arch" type="xml">
43 <form string="Hours Blocks" version="7.0">43 <form string="Hours Blocks" version="7.0">
44 <sheet>44 <header>
45 <h1>45 <button name="action_send_block" type="object" string="Send by Email" class="oe_highlight"/>
46 <field name="invoice_id" placeholder="Choose an invoice..."/>46 </header>
47 <label for="type" string="Based on:" class="oe_inline"/>47 <sheet>
48 <field name="type" class="oe_inline"/>48 <h1>
49 </h1>49 <field name="invoice_id" placeholder="Choose an invoice..."/>
5050 <label for="type" string="Based on:" class="oe_inline"/>
51 <group>51 <field name="type" class="oe_inline"/>
52 <field name="last_action_date" />52 </h1>
53 <field name="close_date" />53
54 </group>54 <group>
5555 <field name="last_action_date" />
56 <group>56 <field name="close_date" />
57 <separator colspan="4" string="Hours Quantity / Amount"/>57 </group>
58 <field name="amount_hours_block" string="Bought"/>58
59 <field name="amount_hours_block_done" string="Used"/>59 <group>
60 <field name="amount_hours_block_delta" string="Difference"/>60 <separator colspan="4" string="Hours Quantity / Amount"/>
61 </group>61 <field name="amount_hours_block" string="Bought"/>
6262 <field name="amount_hours_block_done" string="Used"/>
63 <group>63 <field name="amount_hours_block_delta" string="Difference"/>
64 <separator colspan="4" string="Invoice's related information"/>64 </group>
65 <field name="date_invoice"/>65
66 <field name="name"/>66 <group>
67 <field name="number"/>67 <separator colspan="4" string="Invoice's related information"/>
68 <field name="partner_id" groups="base.group_user"/>68 <field name="date_invoice"/>
69 <field name="user_id"/>69 <field name="name"/>
70 <field name="company_id" groups="base.group_multi_company" widget="selection"/>70 <field name="number"/>
7171 <field name="partner_id" groups="base.group_user"/>
72 <field name="journal_id" invisible="1"/>72 <field name="user_id"/>
73 <field name="period_id" invisible="1" groups="account.group_account_user"/>73 <field name="company_id" groups="base.group_multi_company" widget="selection"/>
7474
75 <field name="currency_id"/>75 <field name="journal_id" invisible="1"/>
76 <newline/>76 <field name="period_id" invisible="1" groups="account.group_account_user"/>
77 <field name="residual" sum="Residual Amount"/>77
78 <field name="amount_total" sum="Total Amount"/>78 <field name="currency_id"/>
79 <field name="state"/>79 <newline/>
80 </group>80 <field name="residual" sum="Residual Amount"/>
81 </sheet>81 <field name="amount_total" sum="Total Amount"/>
82 <field name="state"/>
83 </group>
84 </sheet>
85 <div class="oe_chatter">
86 <field name="message_follower_ids" widget="mail_followers"/>
87 <field name="message_ids" widget="mail_thread"/>
88 </div>
82 </form>89 </form>
83 </field>90 </field>
84 </record>91 </record>
8592
=== added directory 'analytic_hours_block/i18n'
=== added file 'analytic_hours_block/i18n/analytic_hours_block.pot'
--- analytic_hours_block/i18n/analytic_hours_block.pot 1970-01-01 00:00:00 +0000
+++ analytic_hours_block/i18n/analytic_hours_block.pot 2014-01-31 14:46:22 +0000
@@ -0,0 +1,460 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * analytic_hours_block
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-01-08 12:49+0000\n"
10"PO-Revision-Date: 2014-01-08 12:49+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: analytic_hours_block
19#: report:account.hours.block:0
20msgid "Maintenance And Support Summary"
21msgstr ""
22
23#. module: analytic_hours_block
24#: report:account.hours.block:0
25msgid "Invoice Date:"
26msgstr ""
27
28#. module: analytic_hours_block
29#: view:account.hours.block:0
30msgid "Group By..."
31msgstr ""
32
33#. module: analytic_hours_block
34#: view:account.hours.block:0
35msgid "Bought"
36msgstr ""
37
38#. module: analytic_hours_block
39#: field:account.hours.block,close_date:0
40msgid "Closed Date"
41msgstr ""
42
43#. module: analytic_hours_block
44#: field:account.hours.block,message_unread:0
45msgid "Unread Messages"
46msgstr ""
47
48#. module: analytic_hours_block
49#: field:account.hours.block,company_id:0
50msgid "Company"
51msgstr ""
52
53#. module: analytic_hours_block
54#: field:account.hours.block,date_invoice:0
55msgid "Invoice Date"
56msgstr ""
57
58#. module: analytic_hours_block
59#: field:account.hours.block,residual:0
60msgid "Residual"
61msgstr ""
62
63#. module: analytic_hours_block
64#: help:account.hours.block,amount_hours_block:0
65msgid "Amount bought by the customer. This amount is expressed in the base Unit of Measure (factor=1.0)"
66msgstr ""
67
68#. module: analytic_hours_block
69#: view:account.hours.block:0
70msgid "Based on:"
71msgstr ""
72
73#. module: analytic_hours_block
74#: field:account.hours.block,message_ids:0
75msgid "Messages"
76msgstr ""
77
78#. module: analytic_hours_block
79#: selection:account.hours.block,type:0
80msgid "Amount"
81msgstr ""
82
83#. module: analytic_hours_block
84#: selection:account.hours.block,state:0
85msgid "Cancelled"
86msgstr ""
87
88#. module: analytic_hours_block
89#: help:account.hours.block,message_unread:0
90msgid "If checked new messages require your attention."
91msgstr ""
92
93#. module: analytic_hours_block
94#: model:email.template,body_html:analytic_hours_block.email_template_hours_block
95msgid "\n"
96" Here is your Hours Block Report\n"
97" "
98msgstr ""
99
100#. module: analytic_hours_block
101#: view:account.hours.block:0
102msgid "Hours Quantity / Amount"
103msgstr ""
104
105#. module: analytic_hours_block
106#: report:account.hours.block:0
107msgid "Remaining hours:"
108msgstr ""
109
110#. module: analytic_hours_block
111#: report:account.hours.block:0
112msgid "Quantity of hours bought:"
113msgstr ""
114
115#. module: analytic_hours_block
116#: help:account.hours.block,message_summary:0
117msgid "Holds the Chatter summary (number of messages, ...). This summary is directly in html format in order to be inserted in kanban views."
118msgstr ""
119
120#. module: analytic_hours_block
121#: view:account.hours.block:0
122msgid "Quantity of hours bought"
123msgstr ""
124
125#. module: analytic_hours_block
126#: view:account.hours.block:0
127#: field:account.hours.block,partner_id:0
128msgid "Partner"
129msgstr ""
130
131#. module: analytic_hours_block
132#: view:account.hours.block:0
133msgid "Quantity of hours difference"
134msgstr ""
135
136#. module: analytic_hours_block
137#: field:account.hours.block,period_id:0
138msgid "Period"
139msgstr ""
140
141#. module: analytic_hours_block
142#: field:account.hours.block,state:0
143msgid "State"
144msgstr ""
145
146#. module: analytic_hours_block
147#: field:account.hours.block,message_follower_ids:0
148msgid "Followers"
149msgstr ""
150
151#. module: analytic_hours_block
152#: view:account.hours.block:0
153msgid "Send by Email"
154msgstr ""
155
156#. module: analytic_hours_block
157#: view:account.hours.block:0
158msgid "All Running Hours Block"
159msgstr ""
160
161#. module: analytic_hours_block
162#: field:account.hours.block,last_action_date:0
163msgid "Last action date"
164msgstr ""
165
166#. module: analytic_hours_block
167#: selection:account.hours.block,type:0
168msgid "Hours"
169msgstr ""
170
171#. module: analytic_hours_block
172#: report:account.hours.block:0
173msgid "Description:"
174msgstr ""
175
176#. module: analytic_hours_block
177#: help:account.hours.block,type:0
178msgid "The block is based on the quantity of hours or on the amount."
179msgstr ""
180
181#. module: analytic_hours_block
182#: model:email.template,report_name:analytic_hours_block.email_template_hours_block
183msgid "Hours_Block_${(object.number or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''}"
184msgstr ""
185
186#. module: analytic_hours_block
187#: report:account.hours.block:0
188msgid "Remaining amount:"
189msgstr ""
190
191#. module: analytic_hours_block
192#: model:ir.model,name:analytic_hours_block.model_account_hours_block
193msgid "account.hours.block"
194msgstr ""
195
196#. module: analytic_hours_block
197#: field:account.hours.block,amount_hours_block:0
198msgid "Quantity / Amount bought"
199msgstr ""
200
201#. module: analytic_hours_block
202#: model:ir.actions.report.xml,name:analytic_hours_block.block_hours_report
203msgid "Block Hours State"
204msgstr ""
205
206#. module: analytic_hours_block
207#: view:account.hours.block:0
208msgid "Choose an invoice..."
209msgstr ""
210
211#. module: analytic_hours_block
212#: selection:account.hours.block,state:0
213msgid "Open"
214msgstr ""
215
216#. module: analytic_hours_block
217#: view:account.hours.block:0
218msgid "My invoices"
219msgstr ""
220
221#. module: analytic_hours_block
222#: view:account.hours.block:0
223msgid "Draft Hours Blocks"
224msgstr ""
225
226#. module: analytic_hours_block
227#: field:account.hours.block,currency_id:0
228msgid "Currency"
229msgstr ""
230
231#. module: analytic_hours_block
232#: view:account.hours.block:0
233#: field:account.hours.block,user_id:0
234msgid "Salesman"
235msgstr ""
236
237#. module: analytic_hours_block
238#: view:account.hours.block:0
239msgid "Quantity of hours used"
240msgstr ""
241
242#. module: analytic_hours_block
243#: view:account.hours.block:0
244#: selection:account.hours.block,state:0
245msgid "Draft"
246msgstr ""
247
248#. module: analytic_hours_block
249#: view:account.hours.block:0
250#: model:ir.actions.act_window,name:analytic_hours_block.action_all_block_hour
251msgid "Hours Blocks"
252msgstr ""
253
254#. module: analytic_hours_block
255#: field:account.hours.block,type:0
256msgid "Type of Block"
257msgstr ""
258
259#. module: analytic_hours_block
260#: view:account.hours.block:0
261msgid "Used"
262msgstr ""
263
264#. module: analytic_hours_block
265#: view:account.hours.block:0
266msgid "Total Amount"
267msgstr ""
268
269#. module: analytic_hours_block
270#: selection:account.hours.block,state:0
271msgid "Paid"
272msgstr ""
273
274#. module: analytic_hours_block
275#: report:account.hours.block:0
276msgid "Page"
277msgstr ""
278
279#. module: analytic_hours_block
280#: field:account.hours.block,message_is_follower:0
281msgid "Is a Follower"
282msgstr ""
283
284#. module: analytic_hours_block
285#: report:account.hours.block:0
286msgid "Date"
287msgstr ""
288
289#. module: analytic_hours_block
290#: field:account.invoice,account_hours_block_ids:0
291#: model:ir.actions.act_window,name:analytic_hours_block.act_hours_block_from_invoice
292#: model:ir.ui.menu,name:analytic_hours_block.action_all_block_hour_account
293msgid "Hours Block"
294msgstr ""
295
296#. module: analytic_hours_block
297#: help:account.hours.block,last_action_date:0
298msgid "Date of the last analytic line linked to the invoice related to this block hours."
299msgstr ""
300
301#. module: analytic_hours_block
302#: report:account.hours.block:0
303msgid "Report Date:"
304msgstr ""
305
306#. module: analytic_hours_block
307#: model:email.template,subject:analytic_hours_block.email_template_hours_block
308msgid "${object.company_id.name} Hours Block (Ref ${object.number or 'n/a'})"
309msgstr ""
310
311#. module: analytic_hours_block
312#: view:account.hours.block:0
313msgid "Invoice's related information"
314msgstr ""
315
316#. module: analytic_hours_block
317#: view:account.hours.block:0
318msgid "Search Invoice"
319msgstr ""
320
321#. module: analytic_hours_block
322#: report:account.hours.block:0
323msgid "Quantity"
324msgstr ""
325
326#. module: analytic_hours_block
327#: help:account.hours.block,amount_hours_block_delta:0
328msgid "Difference between bought and used. This amount is expressed in the base Unit of Measure (factor=1.0)"
329msgstr ""
330
331#. module: analytic_hours_block
332#: report:account.hours.block:0
333msgid "0.6cm 27.9cm 20.3cm 27.9cm"
334msgstr ""
335
336#. module: analytic_hours_block
337#: view:account.hours.block:0
338msgid "Residual Amount"
339msgstr ""
340
341#. module: analytic_hours_block
342#: view:account.hours.block:0
343msgid "Overdue Hours Block"
344msgstr ""
345
346#. module: analytic_hours_block
347#: report:account.hours.block:0
348msgid "Amount used:"
349msgstr ""
350
351#. module: analytic_hours_block
352#: field:account.hours.block,number:0
353msgid "Number"
354msgstr ""
355
356#. module: analytic_hours_block
357#: view:account.hours.block:0
358#: field:account.hours.block,invoice_id:0
359#: model:ir.actions.act_window,name:analytic_hours_block.act_invoice_from_hours_block
360#: model:ir.model,name:analytic_hours_block.model_account_invoice
361msgid "Invoice"
362msgstr ""
363
364#. module: analytic_hours_block
365#: selection:account.hours.block,state:0
366msgid "Pro-forma"
367msgstr ""
368
369#. module: analytic_hours_block
370#: view:account.hours.block:0
371msgid "Responsible"
372msgstr ""
373
374#. module: analytic_hours_block
375#: report:account.hours.block:0
376#: field:account.hours.block,name:0
377msgid "Description"
378msgstr ""
379
380#. module: analytic_hours_block
381#: report:account.hours.block:0
382msgid "Amount bought:"
383msgstr ""
384
385#. module: analytic_hours_block
386#: help:account.hours.block,amount_hours_block_done:0
387msgid "Amount done by the staff. This amount is expressed in the base Unit of Measure (factor=1.0)"
388msgstr ""
389
390#. module: analytic_hours_block
391#: report:account.hours.block:0
392msgid "Quantity of hours used:"
393msgstr ""
394
395#. module: analytic_hours_block
396#: report:account.hours.block:0
397msgid "Invoicing"
398msgstr ""
399
400#. module: analytic_hours_block
401#: field:account.hours.block,amount_hours_block_done:0
402msgid "Quantity / Amount used"
403msgstr ""
404
405#. module: analytic_hours_block
406#: field:account.hours.block,journal_id:0
407msgid "Journal"
408msgstr ""
409
410#. module: analytic_hours_block
411#: view:account.hours.block:0
412msgid "Running"
413msgstr ""
414
415#. module: analytic_hours_block
416#: view:account.hours.block:0
417#: field:account.hours.block,amount_hours_block_delta:0
418msgid "Difference"
419msgstr ""
420
421#. module: analytic_hours_block
422#: model:ir.actions.act_window,name:analytic_hours_block.act_block_hour_from_partner
423msgid "All blocks hours"
424msgstr ""
425
426#. module: analytic_hours_block
427#: report:account.hours.block:0
428msgid "Deduced"
429msgstr ""
430
431#. module: analytic_hours_block
432#: model:ir.actions.act_window,name:analytic_hours_block.act_analytic_lines_from_hours_block
433msgid "Analytic Lines"
434msgstr ""
435
436#. module: analytic_hours_block
437#: view:account.hours.block:0
438msgid "Invoice State"
439msgstr ""
440
441#. module: analytic_hours_block
442#: field:account.hours.block,message_summary:0
443msgid "Summary"
444msgstr ""
445
446#. module: analytic_hours_block
447#: help:account.hours.block,message_ids:0
448msgid "Messages and communication history"
449msgstr ""
450
451#. module: analytic_hours_block
452#: view:account.hours.block:0
453msgid "Overdue"
454msgstr ""
455
456#. module: analytic_hours_block
457#: field:account.hours.block,amount_total:0
458msgid "Total"
459msgstr ""
460

Subscribers

People subscribed via source and target branches