DBA Data[Home] [Help]

PACKAGE BODY: APPS.INV_MATERIAL_ALLOCATIONS_GRP

Source


1 PACKAGE BODY inv_material_allocations_grp AS
2   /* $Header: INVMTALB.pls 120.2 2008/04/01 10:46:52 ksivasa ship $*/
3 
4 /*
5 This package manages material allocations in MMTT, MTLT, MSNT along with related
6 interactions with move orders and WIP material requirements. Some of the APIS here
7 are not meant to be called in isolation. For example, reduce_allocation_header
8 is called in conjunction with subsequent calls to APIs as add_serial,
9 remove_serial, update_lot, inv_trx_util_pub.insert_lot_trx. If proper care is
10 not exercised in calling them in conjunction, the state of allocations
11 can become invalid.
12 */
13 
14 g_pkg_name    CONSTANT VARCHAR2(50):= 'inv_material_allocations_grp';
15 g_module_name CONSTANT VARCHAR2(60):= 'inv.plsql.' || g_pkg_name;
16 
17 --A helper function to fetch necessary information from MMTT for further processing.
18 function get_mmtt_info(
19   p_transaction_temp_id   IN            NUMBER,
20   x_primary_mmtt_qty      OUT NOCOPY    NUMBER,
21   x_tx_qty                OUT NOCOPY    NUMBER,
22   x_move_order_line_id    OUT NOCOPY    NUMBER,
23   x_item_primary_uom_code OUT NOCOPY    VARCHAR2,
24   x_transaction_uom       OUT NOCOPY    VARCHAR2,
25   x_inventory_item_id     OUT NOCOPY    NUMBER
26 ) return boolean IS
27   l_module  constant varchar2(200) := g_module_name||'.get_mmtt_info';
28   l_log CONSTANT NUMBER := fnd_log.g_current_runtime_level;
29   l_elog  CONSTANT boolean := ((FND_LOG.LEVEL_EXCEPTION >= l_log) and FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
30   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= l_log));
31   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= l_log));
32 begin
33   --get primary qty from MMTT
34   select primary_quantity, transaction_quantity, move_order_line_id,
35   item_primary_uom_code, transaction_uom, inventory_item_id
36   into x_primary_mmtt_qty, x_tx_qty, x_move_order_line_id,
37   x_item_primary_uom_code, x_transaction_uom, x_inventory_item_id
38   from mtl_material_transactions_temp
39   where transaction_temp_id = p_transaction_temp_id;
40 
41   if (l_slog) then
42     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
43     'MMTT: x_primary_mmtt_qty=' || x_primary_mmtt_qty|| ',x_tx_qty=' || x_tx_qty
44     || ',x_move_order_line_id=' || x_move_order_line_id
45     || ',x_item_primary_uom_code=' || x_item_primary_uom_code
46     || ',x_transaction_uom='|| x_transaction_uom
47     || ',x_inventory_item_id='  ||  x_inventory_item_id
48     );
49   end if;
50   return true;
51 exception
52 when no_data_found then
53   if (l_elog) then
54     FND_LOG.STRING(FND_LOG.LEVEL_EXCEPTION, l_module,
55     'Transaction Temp Id '|| p_transaction_temp_id || ' not found');
56   end if;
57   fnd_message.set_name('INV', 'INV_ALLOCATION_NOT_FOUND');
58   fnd_msg_pub.add;
59   return false;
60 WHEN OTHERS THEN
61   if (l_slog) then
62     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
63     'Unhandled exception in get_mmtt_info');
64   end if;
65   return false;
66 end get_mmtt_info;
67 
68 /* A private procedure to reduce a move order line. This is useful in cases when
69 after reducing a allocation, we also want to reduce the move order and optionally
70 the WIP requirements for this material
71 */
72 procedure reduce_move_order(
73   p_move_order_line_id in  number,
74   p_qty_to_reduce in number,
75   p_reduce_wip_requirements in varchar2
76 ) IS
77   l_module  constant varchar2(200) := g_module_name||'.reduce_move_order';
78   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
79     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
80   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
81   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
82   l_txn_source_id    number;
83   l_inventory_item_id number;
84   l_operation_seq_num number;
85   l_organization_id number;
86 begin
87   -- Propagate changes to Move Order header,line and WRO if propagate parameter is set
88   -- As per Inventory, if a move order line has no allocations, it should be
89   -- closed (status 5), not cancelled (status 6)
90   update mtl_txn_request_lines     --overpicking not supported for eam
91   set quantity = quantity - p_qty_to_reduce,
92   quantity_detailed = quantity_detailed - p_qty_to_reduce,
93   line_status = decode(quantity,p_qty_to_reduce,5,line_status),
94   status_date = sysdate            -- BUG 5636266
95   where line_id = p_move_order_line_id
96   returning txn_source_id, inventory_item_id,txn_source_line_id,organization_id
97   into l_txn_source_id, l_inventory_item_id,l_operation_seq_num,l_organization_id;
98 
99   if ((p_reduce_wip_requirements is null) or (p_reduce_wip_requirements= 'Y')) then
100     if (l_slog) then
101       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
102       'MTRL: l_txn_source_id (wip entity id)=' || l_txn_source_id );
103     end if;
104     update wip_requirement_operations
105     set quantity_allocated = quantity_allocated - p_qty_to_reduce
106     where organization_id = l_organization_id
107     and wip_entity_id = l_txn_source_id
108     and operation_seq_num=l_operation_seq_num
109     and inventory_item_id = l_inventory_item_id;
110   end if;
111 end reduce_move_order;
112 
113 /* This procedure deletes a allocation and reduces the move order and WIP material
114 requirements by a corresponding amount. Thus this is to be used when the allocated
115 material is no longer wanted by the requestor.
116 */
117 PROCEDURE delete_allocation(
118   p_init_msg_list         IN            VARCHAR2,
119   p_commit                IN            VARCHAR2,
120   p_transaction_temp_id   IN            NUMBER,
121   x_return_status         OUT NOCOPY    VARCHAR2,
122   x_msg_count             OUT NOCOPY    NUMBER,
123   x_msg_data              OUT NOCOPY    VARCHAR2
124 ) IS
125   l_module              constant varchar2(200) := g_module_name||'.delete_allocation';
126   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
127     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
128   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
129   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
130   l_primary_mmtt_qty    number;
131   l_tx_qty              number;
132   l_move_order_line_id  number;
133   l_dummy_v             varchar2(3);
134   l_dummy_n             number;
135 BEGIN
136   SAVEPOINT DELETE_ALLOCATION;
137   IF FND_API.to_Boolean( p_init_msg_list ) THEN
138     FND_MSG_PUB.initialize;
139   END IF;
140   x_return_status := FND_API.G_RET_STS_SUCCESS;
141   x_msg_count := 0;
142 
143   if (l_plog) then
144     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
145     'Start of '||l_module ||'('||'p_transaction_temp_id='||p_transaction_temp_id||')');
146   end if;
147 
148   --API start
149   --get primary qty and other information from MMTT
150   --Later on can reduce dependance on this by optional parameters which give this
151   --information(saves a db hit). If these are not provided, then we cn query up MMTT
152   if (not get_mmtt_info(p_transaction_temp_id,l_primary_mmtt_qty,
153   l_tx_qty, l_move_order_line_id, l_dummy_v, l_dummy_v, l_dummy_n)) then
154     FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
155     x_return_status  := fnd_api.g_ret_sts_error;
156     return;
157   end if;
158   --Reduce the allocation quantities in Move order headers, lines and in WRO
159   reduce_move_order(l_move_order_line_id, l_primary_mmtt_qty, 'Y');
160   if (l_slog) then
161     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
162     'Calling inv_trx_util_pub.delete_transaction');
163   end if;
164   --Call the inventory delete API.
165   --This API is similar to the wrapper inv_mo_line_detail_util.delete_allocation
166   inv_trx_util_pub.delete_transaction(
167       x_return_status       => x_return_status
168     , x_msg_data            => x_msg_data
169     , x_msg_count           => x_msg_count
170     , p_transaction_temp_id => p_transaction_temp_id
171   );
172   if (l_slog) then
173     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
174      'inv_trx_util_pub.delete_transaction returns. Return status='
175      || x_return_status|| ', Message Count = '|| x_msg_count
176      || ', Message data=' || REPLACE(x_msg_data, CHR(0), ' '));
177   end if;
178   if (x_return_status <> FND_API.G_RET_STS_SUCCESS) then
179     raise fnd_api.g_exc_error;
180   end if;
181   --API end
182 
183   IF FND_API.To_Boolean( p_commit ) THEN
184     COMMIT WORK;
185   END IF;
186   x_return_status := FND_API.G_RET_STS_SUCCESS;
187   FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
188   if (l_plog) then
189     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
190   end if;
191 
192 EXCEPTION
193 WHEN fnd_api.g_exc_error THEN
194   x_return_status  := fnd_api.g_ret_sts_error;
195   fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
196   ROLLBACK to delete_allocation;
197 WHEN OTHERS THEN
198   x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
199   FND_MSG_PUB.Count_And_Get(
200     p_count           =>      x_msg_count,
201     p_data            =>      x_msg_data);
202   ROLLBACK to delete_allocation;
203 end delete_allocation;
204 
205 /* Reduces the allocation header at the MMTT level and reduces the move order
206 and WIP material requirements by a corresponding amount. Thus this is to be used
207 when the requestor wants to reduce his requirement and free up the allocation.
208 For lot and/or serial controlled items, this API is to be followed by subsequent
209 calls to other APIs to adjust the lot and serial allocations.
210 */
211 PROCEDURE reduce_allocation_header(
212   p_init_msg_list            IN            VARCHAR2,
213   p_commit                   IN            VARCHAR2,
214   p_transaction_temp_id      IN            NUMBER,
215   p_organization_id          IN            NUMBER,
216   p_qty_to_reduce            IN            NUMBER,
217   p_final_qty                IN            NUMBER,
218   p_delete_remaining         IN            VARCHAR2,
219   x_new_transaction_temp_id  OUT NOCOPY    NUMBER,
220   x_return_status            OUT NOCOPY    VARCHAR2,
221   x_msg_count                OUT NOCOPY    NUMBER,
222   x_msg_data                 OUT NOCOPY    VARCHAR2
223 ) IS
224   l_module              constant varchar2(200) := g_module_name||'.reduce_allocation_header';
225   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
226     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
227   l_plog CONSTANT boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
228   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
229   l_qty_to_reduce       number;
230   l_final_qty           number;
231   l_final_tx_qty        number;
232   l_primary_mmtt_qty    number;
233   l_tx_qty              number;
234   l_move_order_line_id  number;
235   l_item_primary_uom_code varchar2(3);
236   l_transaction_uom     varchar2(3);
237   l_inventory_item_id   number;
238 BEGIN
239   SAVEPOINT reduce_allocation_header;
240   x_return_status := FND_API.G_RET_STS_SUCCESS;
241   x_msg_count := 0;
242 
243   if (l_plog) then
244     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
245     'Start of ' || l_module || '('
246     || 'p_transaction_temp_id='|| p_transaction_temp_id
247     || ',p_qty_to_reduce='|| p_qty_to_reduce || ',p_final_qty='|| p_final_qty
248     || ',p_delete_remaining='|| p_delete_remaining || ')');
249   end if;
250 
251   --API start
252   --get primary qty and other information from MMTT
253   if (not get_mmtt_info(p_transaction_temp_id,l_primary_mmtt_qty,
254   l_tx_qty, l_move_order_line_id, l_item_primary_uom_code, l_transaction_uom,
255   l_inventory_item_id)) then
256     FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
257     return;
258   end if;
259   --Qty can be entered as either reduction amount (delta) or final reduced amount
260   --Assume that the quantity specified is in terms of primary UOM
261   if (p_qty_to_reduce is not null) then
262     l_final_qty := l_primary_mmtt_qty - p_qty_to_reduce;
263     l_qty_to_reduce := p_qty_to_reduce;
264   else
265     l_final_qty := p_final_qty;
266     l_qty_to_reduce := l_primary_mmtt_qty - p_final_qty;
267   end if;
268   if (l_slog) then
269       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
270         'Calculated l_final_qty='||l_final_qty||
271         ',l_qty_to_reduce='||l_qty_to_reduce);
272     end if;
273   --Validate final qty and if correct, reduce MMTT
274   if (l_final_qty <= 0) then
275     if (l_elog) then
276       FND_LOG.STRING(FND_LOG.LEVEL_EXCEPTION, l_module, 'Cannot reduce qty to below 0');
277     end if;
278     fnd_message.set_name('INV', 'INV_NON_POSITIVE_ISSUE_QTY');
279     fnd_msg_pub.add;
280     FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
281     return;
282   --Following elsif (3 lines): not sure whether we should allow delete here
283   --also or only in delete_allocation
284   --elsif (l_final_qty = 0) then
285   --  delete mtl_material_transactions_temp
286   --  where transaction_temp_id = p_transaction_temp_id;
287   else
288     -- Convert the count quantity into the item primary uom quantity
289     l_final_tx_qty :=
290       inv_convert.inv_um_convert ( l_inventory_item_id,
291                                   5,
292                                   l_final_qty,
293                                   l_item_primary_uom_code,
294                                   l_transaction_uom,
295                                   NULL,
296                                   NULL
297                                 );
298     update mtl_material_transactions_temp
299     set primary_quantity = l_final_qty,  --following line converts between base to tx uom
300     transaction_quantity = l_final_tx_qty
301     where transaction_temp_id = p_transaction_temp_id;
302   end if;
303 
304   if (p_delete_remaining is not null and (p_delete_remaining = 'Y')) then
305     --Reduce the allocation quantities in Move order headers, lines and in WRO
306     reduce_move_order(l_move_order_line_id, l_qty_to_reduce, 'Y');
307   elsif (l_qty_to_reduce > 0) then
308     -- save the remainder allocation by splitting current allocation.
309     if (l_slog) then
310       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
311         'Calling inv_trx_util_pub.copy_insert_line_trx');
312     end if;
313     --call the split API passing in current transaction temp id, split qty
314     inv_trx_util_pub.copy_insert_line_trx(
315       x_return_status       => x_return_status
316     , x_msg_data            => x_msg_data
317     , x_msg_count           => x_msg_count
318     , x_new_txn_temp_id     => x_new_transaction_temp_id
319     , p_transaction_temp_id => p_transaction_temp_id
320     , p_organization_id     => p_organization_id
321     , p_txn_qty             => l_qty_to_reduce
322     , p_primary_qty         => l_qty_to_reduce
323     );
324     if (l_slog) then
325       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
326        'inv_trx_util_pub.copy_insert_line_trx returns. Return status='
327        || x_return_status|| ', Message Count = '|| x_msg_count
328        || 'x_new_txn_temp_id='|| x_new_transaction_temp_id
329        || ', Message data=' || REPLACE(x_msg_data, CHR(0), ' '));
330     end if;
331     if (x_return_status <> FND_API.G_RET_STS_SUCCESS) then
332       raise fnd_api.g_exc_error;
333     end if;
334   end if;
335   --API end
336 
337   IF FND_API.To_Boolean( p_commit ) THEN
338     COMMIT WORK;
339   END IF;
340   x_return_status := FND_API.G_RET_STS_SUCCESS;
341   FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
342   if (l_plog) then
343     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
344   end if;
345 
346 EXCEPTION
347 WHEN fnd_api.g_exc_error THEN
348   x_return_status  := fnd_api.g_ret_sts_error;
349   fnd_msg_pub.count_and_get(p_count => x_msg_count, p_data => x_msg_data);
350   ROLLBACK to reduce_allocation_header;
351 WHEN OTHERS THEN
352   x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
353   FND_MSG_PUB.Count_And_Get(
354     p_count           =>      x_msg_count,
355     p_data            =>      x_msg_data);
356   ROLLBACK to reduce_allocation_header;
357 end reduce_allocation_header;
358 
359 /* Removes a serial allocation from MSNT and frees up/unmarks the serial in MSN.
360 Optionally if a new allocation temp id is provided, it can split this serial to
361 the new allocation temp id. This API does not adjust the quantities at the MMTT
362 or MTLT level and assumes that they have been adjusted by another API call.
363 Currently this API assumes that the serial numbers have a range of 1 (the
364 pick release process allocates serial numbers individually, not in ranges), this
365 assumption can be relaxed in the future by first splitting the range into
366 individual rows, then deleting just the row for this serial number.
367 */
368 PROCEDURE remove_serial(
369   p_init_msg_list              IN            VARCHAR2,
370   p_commit                     IN            VARCHAR2,
371   p_transaction_temp_id        IN            NUMBER,
372   p_serial                     IN            VARCHAR2,
373   p_lot                        IN            VARCHAR2,
374   p_inventory_item_id          IN            NUMBER,
375   p_new_transaction_temp_id    IN            NUMBER,
376   x_return_status              OUT NOCOPY    VARCHAR2,
377   x_msg_count                  OUT NOCOPY    NUMBER,
378   x_msg_data                   OUT NOCOPY    VARCHAR2
379 ) IS
380   l_module              constant varchar2(200) := g_module_name||'.remove_serial';
381   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
382     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
383   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
384   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
385 BEGIN
386   SAVEPOINT remove_serial;
387   x_return_status := FND_API.G_RET_STS_SUCCESS;
388   x_msg_count := 0;
389 
390   if (l_plog) then
391     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
392     'Start of ' || l_module || '('
393     || 'p_transaction_temp_id='|| p_transaction_temp_id
394     || ',p_inventory_item_id='|| p_inventory_item_id
395     || ',p_serial='|| p_serial || ',p_lot='|| p_lot
396     || ',p_new_transaction_temp_id='|| p_new_transaction_temp_id ||')');
397   end if;
398 
399   --API start
400   if (p_new_transaction_temp_id is not null) then
401     --replace the transaction_temp_id for msnt row with this one.
402     UPDATE mtl_serial_numbers_temp
403        SET transaction_temp_id = p_new_transaction_temp_id
404      WHERE transaction_temp_id = p_transaction_temp_id
405        AND fm_serial_number = p_serial;
406      --restamp the group mark id in msn. needed for bug 2798128 (expects temp id)
407     UPDATE mtl_serial_numbers
408        SET group_mark_id = p_new_transaction_temp_id
409      WHERE group_mark_id = p_transaction_temp_id
410        AND serial_number = p_serial;
411   else
412     --delete current msnt row and then unmark serial
413     DELETE FROM mtl_serial_numbers_temp
414     WHERE transaction_temp_id = p_transaction_temp_id
415     and fm_serial_number = p_serial;
416     --Can also use serial_check.inv_unmark_serial
417     UPDATE mtl_serial_numbers
418        SET line_mark_id = -1
419          , group_mark_id = -1
420          , lot_line_mark_id = -1
421      WHERE inventory_item_id = p_inventory_item_id  --no need of org id, item and serial are unique
422        AND serial_number = p_serial;
423   end if;
424   --API end
425 
426   IF FND_API.To_Boolean( p_commit ) THEN
427     COMMIT WORK;
428   END IF;
429   x_return_status := FND_API.G_RET_STS_SUCCESS;
430   FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
431   if (l_plog) then
432     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
433   end if;
434 
435 EXCEPTION
436   WHEN OTHERS THEN
437     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
438     FND_MSG_PUB.Count_And_Get(
439       p_count           =>      x_msg_count,
440       p_data            =>      x_msg_data);
441     ROLLBACK to remove_serial;
442 end remove_serial;
443 
444 /* Adds a serial allocation to MSNT and reserves/marks the serial in MSN.
445 This API does not adjust the quantities at the MMTT or MTLT level and assumes
446 that they have been adjusted by another API call.
447 */
448 PROCEDURE add_serial(
449   p_init_msg_list              IN            VARCHAR2,
450   p_commit                     IN            VARCHAR2,
451   p_transaction_temp_id        IN            NUMBER,
452   p_organization_id            IN            NUMBER,
453   p_inventory_item_id          IN            NUMBER,
454   p_serial                     IN            VARCHAR2,
455   x_return_status              OUT NOCOPY    VARCHAR2,
456   x_msg_count                  OUT NOCOPY    NUMBER,
457   x_msg_data                   OUT NOCOPY    VARCHAR2
458 ) IS
459   l_module              constant varchar2(200) := g_module_name||'.add_serial';
460   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
461     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
462   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
463   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
464   l_update_count number;
465   l_insert_err_code number;
466 BEGIN
467   SAVEPOINT add_serial;
468   x_return_status := FND_API.G_RET_STS_SUCCESS;
469   x_msg_count := 0;
470 
471   if (l_plog) then
472     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
473     'Start of ' || l_module || '('  ||
474     'p_transaction_temp_id='|| p_transaction_temp_id ||
475     'p_organization_id='|| p_organization_id ||
476     'p_inventory_item_id='|| p_inventory_item_id ||
477     ',p_serial='|| p_serial ||')');
478   end if;
479 
480   --API start
481   l_insert_err_code := inv_trx_util_pub.insert_ser_trx(
482     p_trx_tmp_id     => p_transaction_temp_id,
483     p_user_id        => FND_GLOBAL.USER_ID,
484     p_fm_ser_num     => p_serial,
485     p_to_ser_num     => p_serial,
486     x_proc_msg       => x_msg_data);
487   --Restamping group_mark_id in MSN as transaction temp id. The default from
488   --insert_ser_trx or from inv_mark_serial is transaction header id which is
489   --not acceptable because of bug 2798128 (expects temp id, not hdr id)
490   if (l_insert_err_code = 0) then   -- 0 = success
491     UPDATE mtl_serial_numbers
492        SET group_mark_id = p_transaction_temp_id
493      WHERE serial_number = p_serial
494        AND current_organization_id = p_organization_id
495        AND inventory_item_id = p_inventory_item_id;
496     l_update_count := SQL%ROWCOUNT;
497   end if;
498 
499   if (l_slog) then
500    FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
501     l_update_count||  ' serials marked in MSN');
502   end if;
503   --API end
504 
505   IF FND_API.To_Boolean( p_commit ) THEN
506     COMMIT WORK;
507   END IF;
508   if (l_insert_err_code = 0) then   -- 0 = success
509     x_return_status := FND_API.G_RET_STS_SUCCESS;
510     FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
511   else
512     x_return_status := FND_API.G_RET_STS_ERROR;
513   end if;
514   if (l_plog) then
515     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
516   end if;
517 
518 EXCEPTION
519   WHEN OTHERS THEN
520     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
521     FND_MSG_PUB.Count_And_Get(
522       p_count           =>      x_msg_count,
523       p_data            =>      x_msg_data);
524     ROLLBACK to add_serial;
525 end add_serial;
526 
527 /* This API serves three functions:
528 1) Update lot quantity (if p_lot_quantity is non zero)
529 2) Delete a lot (if p_lot_quantity is zero)
530 3) Split a lot (if p_lot_quantity is less than current qty and new tx temp id is provided)
531 This API does not adjust the quantities at the MMTT or MSNT level and assumes
532 that they have been adjusted by another API call. Future work may need
533 to be done on the uniqueness of temp id, lot_number and qty combination.
534 */
535 PROCEDURE update_lot(
536   p_init_msg_list              IN            VARCHAR2,
537   p_commit                     IN            VARCHAR2,
538   p_transaction_temp_id        IN            NUMBER,
539   p_serial_transaction_temp_id IN            NUMBER,
540   p_lot                        IN            VARCHAR2,
541   p_lot_quantity               IN            NUMBER,
542   p_old_lot_quantity           IN            NUMBER,
543   p_new_transaction_temp_id    IN            NUMBER,
544   x_ser_trx_id                 OUT NOCOPY    NUMBER,
545   x_return_status              OUT NOCOPY    VARCHAR2,
546   x_msg_count                  OUT NOCOPY    NUMBER,
547   x_msg_data                   OUT NOCOPY    VARCHAR2
548 ) IS
549   l_module    constant varchar2(200) := g_module_name||'.update_lot';
550   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
551     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
552   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
553   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
554   l_update_count number := 0;
555   l_delete_count number := 0;
556   l_insert_ret_status number := null;
557   l_reduction_qty number := null;
558 BEGIN
559   SAVEPOINT reduce_lot;
560   x_return_status := FND_API.G_RET_STS_SUCCESS;
561   x_msg_count := 0;
562 
563   if (l_plog) then
564     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
565     'Start of ' || l_module || '('
566     || 'p_transaction_temp_id='|| p_transaction_temp_id
567     || ' p_serial_transaction_temp_id='|| p_serial_transaction_temp_id
568     || ',p_lot='|| p_lot || ',p_lot_quantity='|| p_lot_quantity
569     || ',p_old_lot_quantity='|| p_old_lot_quantity
570     || ',p_new_transaction_temp_id='|| p_new_transaction_temp_id|| ')');
571   end if;
572 
573   --API start
574   --update the qty of the current row. If qty = 0, delete this row.
575   if (p_lot_quantity > 0) then
576     if (p_serial_transaction_temp_id is not null) then
577       update mtl_transaction_lots_temp
578       set primary_quantity = p_lot_quantity,
579       transaction_quantity = p_lot_quantity
580       where serial_transaction_temp_id = p_serial_transaction_temp_id
581       and transaction_temp_id = p_transaction_temp_id
582       and lot_number = p_lot
583       and primary_quantity = p_old_lot_quantity;
584     else
585       update mtl_transaction_lots_temp
586       set primary_quantity = p_lot_quantity,
587       transaction_quantity = p_lot_quantity
588       where transaction_temp_id = p_transaction_temp_id
589       and lot_number = p_lot
590       and primary_quantity = p_old_lot_quantity
591       and rownum = 1;--update only one row since there is no PK in this table
592                      --and it is discouraged to use rowid: distributed databases
593                      --or partitioning may change it within a transaction
594     end if;
595     l_update_count := SQL%ROWCOUNT;
596     if (l_slog) then
597       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
598       l_update_count || ' row(s) updated in MTLT');
599     end if;
600     l_reduction_qty := (p_old_lot_quantity - p_lot_quantity);
601     if (p_new_transaction_temp_id is not null and (l_reduction_qty >0)) then
602       --split this mtlt row under a new MMTT row with remaining qty
603       if (l_slog) then
604         FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
605         'Calling inv_trx_util_pub.insert_lot_trx('|| 'p_pri_qty=p_trx_qty='|| l_reduction_qty);
606       end if;
607       l_insert_ret_status := inv_trx_util_pub.insert_lot_trx(
608         p_trx_tmp_id => p_new_transaction_temp_id
609       , p_user_id    => fnd_global.user_id
610       , p_lot_number => p_lot
611       , p_trx_qty    => l_reduction_qty
612       , p_pri_qty    => l_reduction_qty
613       , x_proc_msg   => x_msg_data
614       , x_ser_trx_id => x_ser_trx_id);
615       if (l_slog) then
616         FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
617         'inv_trx_util_pub.insert_lot_trx returned: Status='||
618         l_insert_ret_status|| ' (0 success, -1 failure)'||
619         ', Return Message='|| x_msg_data|| ', Serial Temp Id='||
620         x_ser_trx_id);
621       end if;
622     end if;
623   elsif (p_lot_quantity = 0) then
624     delete from mtl_transaction_lots_temp
625     where transaction_temp_id = p_transaction_temp_id
626     and lot_number = p_lot
627     and primary_quantity = p_old_lot_quantity
628     and rownum = 1;
629     l_delete_count := SQL%ROWCOUNT;
630     if (l_slog) then
631       FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module,
632       l_delete_count || ' row(s) deleted in MTLT');
633     end if;
634   end if;
635   --API end
636 
637   IF FND_API.To_Boolean( p_commit ) THEN
638     COMMIT WORK;
639   END IF;
640   x_return_status := FND_API.G_RET_STS_SUCCESS;
641   FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
642   if (l_plog) then
643     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
644   end if;
645 
646 EXCEPTION
647   WHEN OTHERS THEN
648     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
649     FND_MSG_PUB.Count_And_Get(
650       p_count           =>      x_msg_count,
651       p_data            =>      x_msg_data);
652     ROLLBACK to reduce_lot;
653 end update_lot;
654 
655 /* Marks a lot row in MTLT with a serial transaction temp id so that
656 child records in MSNT can be inserted for this lot.
657 */
658 PROCEDURE mark_lot_with_ser_temp_id(
659   p_init_msg_list              IN            VARCHAR2,
660   p_commit                     IN            VARCHAR2,
661   p_transaction_temp_id        IN            NUMBER,
662   p_lot                        IN            VARCHAR2,
663   p_primary_quantity           IN            NUMBER,
664   x_ser_trx_id                 OUT NOCOPY    NUMBER,
665   x_return_status              OUT NOCOPY    VARCHAR2,
666   x_msg_count                  OUT NOCOPY    NUMBER,
667   x_msg_data                   OUT NOCOPY    VARCHAR2
668 ) IS
669   l_module    constant varchar2(200) := g_module_name||'.mark_lot_with_ser_temp_id';
670   l_elog  boolean := ((FND_LOG.LEVEL_EXCEPTION >= FND_LOG.G_CURRENT_RUNTIME_LEVEL) and
671     FND_LOG.TEST(FND_LOG.LEVEL_EXCEPTION, l_module));
672   l_plog boolean := (l_elog and (FND_LOG.LEVEL_PROCEDURE >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
673   l_slog boolean := (l_plog and (FND_LOG.LEVEL_STATEMENT >= FND_LOG.G_CURRENT_RUNTIME_LEVEL));
674   l_update_count number := 0;
675   l_ser_trx_id number;
676 BEGIN
677   SAVEPOINT mark_lot_with_ser_temp_id;
678   x_return_status := FND_API.G_RET_STS_ERROR;
679   x_msg_count := 0;
680 
681   if (l_plog) then
682     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module,
683     'Start of ' || l_module || '(' ||'p_commit=' ||p_commit
684      || 'p_transaction_temp_id='|| p_transaction_temp_id
685      || ',p_lot='|| p_lot || ',p_primary_quantity='|| p_primary_quantity|| ')');
686   end if;
687 
688   --API start
689   SELECT MTL_MATERIAL_TRANSACTIONS_S.NEXTVAL into l_ser_trx_id from dual;
690   update mtl_transaction_lots_temp
691     set serial_transaction_temp_id = l_ser_trx_id
692     where transaction_temp_id = p_transaction_temp_id
693     and lot_number = p_lot
694     and primary_quantity = p_primary_quantity
695     and rownum = 1;
696   l_update_count := SQL%ROWCOUNT;
697   if (l_update_count = 1) then
698     x_return_status := FND_API.G_RET_STS_SUCCESS;
699     x_ser_trx_id := l_ser_trx_id;
700   end if;
701   if (l_slog) then
702     FND_LOG.STRING(FND_LOG.LEVEL_STATEMENT, l_module, l_update_count ||
703     ' row(s) updated in MTLT with serial_transaction_temp_id: '|| x_ser_trx_id);
704   end if;
705   --API end
706 
707   IF FND_API.To_Boolean( p_commit ) THEN
708     COMMIT WORK;
709   END IF;
710   FND_MSG_PUB.Count_And_Get('T', x_msg_count, x_msg_data);
711   if (l_plog) then
712     FND_LOG.STRING(FND_LOG.LEVEL_PROCEDURE, l_module, 'End of ' || l_module);
713   end if;
714 
715 EXCEPTION
716   WHEN OTHERS THEN
717     x_return_status := FND_API.G_RET_STS_UNEXP_ERROR ;
718     FND_MSG_PUB.Count_And_Get(
719       p_count           =>      x_msg_count,
720       p_data            =>      x_msg_data);
721     ROLLBACK to mark_lot_with_ser_temp_id;
722 end mark_lot_with_ser_temp_id;
723 
724 END INV_MATERIAL_ALLOCATIONS_GRP;