def nut_report_update(message, args, sub_cmd, **kwargs): """ Client sent an update to an existing report Only the modified fields are sent. Each section is coded accoding to report codes. All fields are coded according to nutrsc. > nut report-update rgaudin -1355030878 0112 #P &SAM 1d:2 " 1h:2 1l6:2 #C &MAM a0:100 #T v:1 w:0 u:0-EOM-""" def resp_error(code, msg): # make sure we cancel whatever addition message.respond(u"nut report-update error %(code)s|%(msg)s" \ % {'code': code, 'msg': msg}) return True def provider_entity(provider): """ Entity a Provider is attached to """ try: return NUTEntity.objects.get(id=provider.first_access().target.id) except: return None # check that all parts made it together if not args.strip().endswith('-eom-'): return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) else: args = args.strip()[:-5].strip() # split up sections sections = {} try: parts = args.strip().lower().split('#') for index in range(0, len(parts)): if index == 0: infos = parts[index] else: sections[parts[index][0].upper()] = parts[index][1:] pec_sec = sections.get('P', '').strip() cons_sec = sections.get('C', '').strip() order_sec = sections.get('O', '').strip() other_sec = sections.get('T', '').strip() except: return resp_error('BAD_FORM', REPORT_ERRORS['BAD_FORM']) # split up infos try: username, pwhash, date_str = infos.strip().split() except: return resp_error('BAD_FORM_INFO', REPORT_ERRORS['BAD_FORM_INFO']) # get Provider based on username try: provider = Provider.objects.get(user__username=username) except Provider.DoesNotExist: return resp_error('NO_ACC', REPORT_ERRORS['NO_ACC']) # check that provider pwhash is good if not provider.check_hash(pwhash): return resp_error('BAD_PASS', REPORT_ERRORS['BAD_PASS']) # check that user is not disabled if not provider.is_active: return resp_error('ACC_DIS', REPORT_ERRORS['ACC_DIS']) # check that user has permission to submit report on entity entity = provider_entity(provider) if not entity: return resp_error('NOT_ENT', REPORT_ERRORS['NOT_ENT']) eentity = Entity.objects.get(id=entity.id) if not provider_can('can_submit_report', provider, eentity): return resp_error('NO_PERM', REPORT_ERRORS['NO_PERM']) # parse date and check if period is valid try: month = int(date_str[0:2]) year = int('%s%s' % ('20', date_str[2:4])) period = MonthPeriod.find_create_from(year=year, month=month) except: return resp_error('BAD_FORM_PERIOD', REPORT_ERRORS['BAD_FORM_PERIOD']) # check period is the one we want if not period == current_reporting_period(): return resp_error('BAD_PERIOD', REPORT_ERRORS['BAD_PERIOD']) # global infos infos = {'entity': entity, 'eentity': eentity, 'provider': provider, 'month': month, 'year': year, 'period': period, 'username': username, 'pwhash': pwhash} # Retrieve report try: nut_report = NutritionReport.objects.get(period=infos['period'], entity=infos['entity'], type=Report.TYPE_SOURCE) except: return resp_error('MISS', REPORT_ERRORS['MISS']) reports = [] # common start of error message error_start = u"Impossible d'enregistrer le rapport. " logger.info("Processing PEC") if pec_sec: subs = pec_sec.split('&') subs = subs[1:] for sub in subs: fields = sub.split() cap = fields[0].lower() sub_report = getattr(nut_report, 'pec_%s_report' % cap) for field in fields[1:]: cfield, value = field.split(':') rfield = uncompress_pec_field(cfield) setattr(sub_report, rfield, int(value)) validator = PECReportValidator(sub_report) validator.errors.reset() try: validator.validate() except AttributeError as e: return resp_error('PEC_%s' % cap.upper(), error_start + e.__str__()) except: pass errors = validator.errors # return first error to user if errors.count() > 0: return resp_error('PEC_%s' % cap.upper(), error_start + errors.all()[0]) else: reports.append(sub_report) logger.info("Processing CONS") if cons_sec: subs = cons_sec.split('&') subs = subs[1:] for sub in subs: fields = sub.split() cap = fields[0].lower() logger.info(cap.upper()) for field in fields[1:]: cfield, value = field.split(':') rinpc, rfield = uncompress_cons_field(cfield) sub_report = getattr(getattr(nut_report, 'cons_%s_report' % cap), 'icr')(rinpc) setattr(sub_report, rfield, int(value)) if sub_report.valid and not sub_report in reports: reports.append(sub_report) logger.info("Processing ORDER") if order_sec: subs = order_sec.split('&') subs = subs[1:] for sub in subs: logger.info("\t%s" % sub) fields = sub.split() cap = fields[0].lower() for field in fields[1:]: cfield, value = field.split(':') rinpc, rfield = uncompress_cons_field(cfield) sub_report = getattr(getattr(nut_report, 'order_%s_report' % cap), 'icr')(rinpc) setattr(sub_report, rfield, int(value)) if not sub_report in reports: reports.append(sub_report) logger.info("Processing OTHER") if other_sec: fields = other_sec.split() for field in fields[1:]: cfield, value = field.split(':') rfield = uncompress_pec_field(cfield) sub_report = nut_report.pec_other_report setattr(sub_report, rfield, int(value)) # check validity relative to PEC if not sub_report.total == sub_report.nut_report.sum_all_other: return resp_error('OTHER_INT', REPORT_ERRORS['OTHER_INT']) else: reports.append(sub_report) # check validity of changes # save to DB @reversion.create_revision() @transaction.commit_manually def save_reports(reports, nut_report, provider=None): reversion.set_user(provider.user) reversion.set_comment("SMS report update") for report in reports: print("saving %s" % report) try: sub_report.save() except: transaction.rollback() return False try: nut_report._status = nut_report.STATUS_MODIFIED_AUTHOR nut_report.modified_by = provider nut_report.save() except: transaction.rollback() return False transaction.commit() return True logger.info("Saving reports") if not save_reports(reports, nut_report, provider): logger.warning("Unable to save reports") return resp_error('SRV', REPORT_ERRORS['SRV']) logger.info("Reports saved") ## CONFIRM RESPONSE confirm = "nut report-update ok %s" % nut_report.receipt message.respond(confirm) return True
def pec_sub_report(message, pec, infos, *args, **kwargs): """ PEC Report part of main Report SMS handling """ def resp_error(code, msg): return (False, (code, msg)) def class_for(cap): return eval("PEC%sReport" % cap.upper()) def holder_for(cap): return eval("PEC%sDataHolder" % cap.upper()) nut_report = kwargs.get("nut_report", None) # store MAM/SAM/SAM+ reports reports = {} ########## CHECK AGES # create Data Holder pec_holder = {} # loop on capabilities for capid, cap in pec.items(): pec_cap = holder_for(capid)() for ageid, age in cap.items(): # match field names with values try: age_data = dict(zip(pec_cap.fields_for(ageid), age.split())) except ValueError: # failure to split means we proabably lack a data or more # we can't process it. return resp_error("BAD_FORM_PEC", REPORT_ERRORS["BAD_FORM_PEC"]) # convert form-data to int or bool respectively try: for key, value in age_data.items(): # all PEC data are integer pec_cap.set(key, int(value)) except: raise # failure to convert means non-numeric # value which we can't process. return resp_error("BAD_FORM_PEC", REPORT_ERRORS["BAD_FORM_PEC"]) # store Data Holder in main variable pec_holder[capid] = pec_cap # Create Validator then Report then store #recipt ID for each CAP for capid, data_browser in pec_holder.items(): # class of the report to create ClassReport = class_for(capid) # create validator and fire validator = PECReportValidator(data_browser) validator.errors.reset() # common start of error message error_start = u"Impossible d'enregistrer le rapport. " try: validator.validate() except AttributeError as e: return resp_error("PEC_%s" % capid.upper(), error_start + e.__str__()) except: pass errors = validator.errors # UNIQUENESS if ClassReport.objects.filter(nut_report=nut_report).count() > 0: return resp_error("UNIQ", REPORT_ERRORS["UNIQ"]) # return first error to user if errors.count() > 0: return resp_error("PEC_%s" % capid.upper(), error_start + errors.all()[0]) # create the report try: report = ClassReport(nut_report=nut_report) report.add_all_data(data_browser) except Exception as e: logger.error(ClassReport) raise logger.error(u"Unable to save report to DB. Message: %s | Exp: %r" % (message.content, e)) return resp_error("SRV", REPORT_ERRORS["SRV"]) reports[capid] = [report] logger.info("END OF PEC") return (True, reports)