Revision 79e3da8a snf-astakos-app/astakos/quotaholder/callpoint.py

b/snf-astakos-app/astakos/quotaholder/callpoint.py
31 31
# interpreted as representing official policies, either expressed
32 32
# or implied, of GRNET S.A.
33 33

  
34
from functools import partial
35

  
34 36
from astakos.quotaholder.exception import (
35 37
    QuotaholderError,
38
    NoCommissionError,
36 39
    CorruptedError, InvalidDataError,
37
    NoCapacityError,
40
    NoHoldingError,
38 41
    DuplicateError)
39 42

  
40 43
from astakos.quotaholder.commission import (
......
311 314
                         context=None,
312 315
                         clientkey=None,
313 316
                         name=None,
317
                         force=False,
314 318
                         provisions=()):
315 319

  
316 320
        if name is None:
......
323 327

  
324 328
        try:
325 329
            checked = []
326
            for holder, source, resource, quantity in provisions:
330
            for provision in provisions:
331
                try:
332
                    holder = provision['holder']
333
                    source = provision['source']
334
                    resource = provision['resource']
335
                    quantity = provision['quantity']
336
                except KeyError:
337
                    raise InvalidDataError("Malformed provision")
327 338

  
328
                if holder == source:
329
                    m = ("Cannot issue commission from a holder "
330
                         "to itself (%s)" % (holder,))
331
                    raise InvalidDataError(m)
339
                if not isinstance(quantity, (int, long)):
340
                    raise InvalidDataError("Malformed provision")
332 341

  
333 342
                ent_res = holder, resource
334 343
                if ent_res in checked:
335 344
                    m = "Duplicate provision for %s.%s" % ent_res
336
                    raise DuplicateError(m)
345
                    details = {'message': m,
346
                               }
347
                    raise DuplicateError(m,
348
                                         provision=provision,
349
                                         details=details)
337 350
                checked.append(ent_res)
338 351

  
339 352
                # Target
......
343 356
                                        source=source,
344 357
                                        for_update=True)
345 358
                except Holding.DoesNotExist:
346
                    m = ("There is no capacity "
347
                         "to allocate into in %s.%s" % (holder, resource))
348
                    raise NoCapacityError(m,
349
                                          holder=holder,
350
                                          resource=resource,
351
                                          requested=quantity,
352
                                          current=0,
353
                                          limit=0)
359
                    m = ("There is no such holding %s.%s"
360
                         % (holder, resource))
361
                    raise NoHoldingError(m,
362
                                         provision=provision)
354 363

  
355 364
                if quantity >= 0:
356
                    operations.prepare(Import, th, quantity)
365
                    operations.prepare(Import, th, quantity, force)
357 366

  
358 367
                else: # release
359 368
                    abs_quantity = -quantity
360
                    operations.prepare(Release, th, abs_quantity)
369
                    operations.prepare(Release, th, abs_quantity, force)
361 370

  
362 371
                Provision.objects.create(serial=commission,
363 372
                                         holding=th,
......
393 402

  
394 403
    def accept_commission(self,
395 404
                          context=None, clientkey=None,
396
                          serials=[], reason=''):
405
                          serial=None, reason=''):
397 406
        log_time = now()
398 407

  
399
        for serial in serials:
400
            try:
401
                c = db_get_commission(clientkey=clientkey, serial=serial,
402
                                      for_update=True)
403
            except Commission.DoesNotExist:
404
                return
405

  
406
            operations = Operations()
408
        try:
409
            c = db_get_commission(clientkey=clientkey, serial=serial,
410
                                  for_update=True)
411
        except Commission.DoesNotExist:
412
            return False
407 413

  
408
            provisions = db_filter_provision(serial=serial, for_update=True)
409
            for pv in provisions:
410
                try:
411
                    th = db_get_holding(id=pv.holding_id,
412
                                        for_update=True)
413
                except Holding.DoesNotExist:
414
                    m = "Corrupted provision"
415
                    raise CorruptedError(m)
414
        operations = Operations()
416 415

  
417
                quantity = pv.quantity
416
        provisions = db_filter_provision(serial=serial, for_update=True)
417
        for pv in provisions:
418
            try:
419
                th = db_get_holding(id=pv.holding_id,
420
                                    for_update=True)
421
            except Holding.DoesNotExist:
422
                m = "Corrupted provision"
423
                raise CorruptedError(m)
418 424

  
419
                if quantity >= 0:
420
                    operations.finalize(Import, th, quantity)
421
                else: # release
422
                    abs_quantity = -quantity
423
                    operations.finalize(Release, th, abs_quantity)
425
            quantity = pv.quantity
424 426

  
425
                reason = 'ACCEPT:' + reason[-121:]
426
                self._log_provision(c, pv, log_time, reason)
427
                pv.delete()
428
            c.delete()
427
            if quantity >= 0:
428
                operations.finalize(Import, th, quantity)
429
            else: # release
430
                abs_quantity = -quantity
431
                operations.finalize(Release, th, abs_quantity)
429 432

  
430
        return
433
            reason = 'ACCEPT:' + reason[-121:]
434
            self._log_provision(c, pv, log_time, reason)
435
            pv.delete()
436
        c.delete()
437
        return True
431 438

  
432 439
    def reject_commission(self,
433 440
                          context=None, clientkey=None,
434
                          serials=[], reason=''):
441
                          serial=None, reason=''):
435 442
        log_time = now()
436 443

  
437
        for serial in serials:
438
            try:
439
                c = db_get_commission(clientkey=clientkey, serial=serial,
440
                                      for_update=True)
441
            except Commission.DoesNotExist:
442
                return
443

  
444
            operations = Operations()
444
        try:
445
            c = db_get_commission(clientkey=clientkey, serial=serial,
446
                                  for_update=True)
447
        except Commission.DoesNotExist:
448
            return False
445 449

  
446
            provisions = db_filter_provision(serial=serial, for_update=True)
447
            for pv in provisions:
448
                try:
449
                    th = db_get_holding(id=pv.holding_id,
450
                                        for_update=True)
451
                except Holding.DoesNotExist:
452
                    m = "Corrupted provision"
453
                    raise CorruptedError(m)
450
        operations = Operations()
454 451

  
455
                quantity = pv.quantity
452
        provisions = db_filter_provision(serial=serial, for_update=True)
453
        for pv in provisions:
454
            try:
455
                th = db_get_holding(id=pv.holding_id,
456
                                    for_update=True)
457
            except Holding.DoesNotExist:
458
                m = "Corrupted provision"
459
                raise CorruptedError(m)
456 460

  
457
                if quantity >= 0:
458
                    operations.undo(Import, th, quantity)
459
                else: # release
460
                    abs_quantity = -quantity
461
                    operations.undo(Release, th, abs_quantity)
461
            quantity = pv.quantity
462 462

  
463
                reason = 'REJECT:' + reason[-121:]
464
                self._log_provision(c, pv, log_time, reason)
465
                pv.delete()
466
            c.delete()
463
            if quantity >= 0:
464
                operations.undo(Import, th, quantity)
465
            else: # release
466
                abs_quantity = -quantity
467
                operations.undo(Release, th, abs_quantity)
467 468

  
468
        return
469
            reason = 'REJECT:' + reason[-121:]
470
            self._log_provision(c, pv, log_time, reason)
471
            pv.delete()
472
        c.delete()
473
        return True
469 474

  
470 475
    def get_pending_commissions(self, context=None, clientkey=None):
471 476
        pending = Commission.objects.filter(clientkey=clientkey)
472 477
        pending_list = pending.values_list('serial', flat=True)
473
        return pending_list
478
        return list(pending_list)
479

  
480
    def get_commission(self, clientkey=None, serial=None):
481
        try:
482
            commission = Commission.objects.get(clientkey=clientkey,
483
                                                serial=serial)
484
        except Commission.DoesNotExist:
485
            raise NoCommissionError(serial)
486

  
487
        objs = Provision.objects.select_related('holding')
488
        provisions = objs.filter(serial=commission)
489

  
490
        ps = [p.todict() for p in provisions]
491

  
492
        response = {'serial':     serial,
493
                    'provisions': ps,
494
                    'issue_time': commission.issue_time,
495
                    }
496
        return response
497

  
498
    def _resolve(self, include, exclude, operation):
499
        done = []
500
        failed = []
501
        for serial in include:
502
            if serial in exclude:
503
                failed.append((serial, 'CONFLICT'))
504
            else:
505
                response = operation(serial=serial)
506
                if response:
507
                    done.append(serial)
508
                else:
509
                    failed.append((serial, 'NOTFOUND'))
510
        return done, failed
474 511

  
475 512
    def resolve_pending_commissions(self,
476 513
                                    context=None, clientkey=None,
477
                                    max_serial=None, accept_set=[]):
514
                                    accept_set=[], reject_set=[]):
478 515
        accept_set = set(accept_set)
479
        pending = self.get_pending_commissions(context=context,
480
                                               clientkey=clientkey)
481
        pending = sorted(pending)
482

  
483
        accept = self.accept_commission
484
        reject = self.reject_commission
516
        reject_set = set(reject_set)
485 517

  
486
        for serial in pending:
487
            if serial > max_serial:
488
                break
518
        accept = partial(self.accept_commission, clientkey=clientkey)
519
        reject = partial(self.reject_commission, clientkey=clientkey)
489 520

  
490
            if serial in accept_set:
491
                accept(context=context, clientkey=clientkey, serials=[serial])
492
            else:
493
                reject(context=context, clientkey=clientkey, serials=[serial])
521
        accepted, failed_ac = self._resolve(accept_set, reject_set, accept)
522
        rejected, failed_re = self._resolve(reject_set, accept_set, reject)
494 523

  
495
        return
524
        failed = list(set(failed_ac + failed_re))
525
        return accepted, rejected, failed
496 526

  
497 527
    def get_timeline(self, context=None, after="", before="Z", get_timeline=[]):
498 528
        holder_set = set()

Also available in: Unified diff