def ignore_payment(transaction, log_user, reason): try: payment = Payment.objects.get(transaction_id=transaction) if not payment.ignore and not payment.billingcycle: payment.ignore = True payment.save() log_change(payment, log_user, change_message="Ignored by manual_matches: %s" % reason) except Payment.DoesNotExist: pass
def process_csv(filename): """Actual CSV file processing logic """ num_attached = num_notattached = 0 sum_attached = sum_notattached = 0 num_nomember = num_nopayment = num_nocycle = num_old = 0 log_user = User.objects.get(id=1) with open(filename, 'r') as f: reader = csv.reader(f) for row in reader: (mid, year, date, reference, transaction) = row try: membership = Membership.objects.get(id=int(mid)) cycle = find_cycle(membership, year) payment = Payment.objects.get(transaction_id=transaction) if payment.billingcycle: # Already assigned, mark cycle as paid if payment.billingcycle != cycle: mark_cycle_paid( cycle, log_user, "One payment for several billing cycles") num_old += 1 continue payment.attach_to_cycle(cycle) log_change(payment, log_user, change_message="Attached by manual_matches") num_attached += 1 sum_attached += payment.amount continue except Membership.DoesNotExist: logger.warning("Membership %s not found. transaction id: %s" % (mid, transaction)) # Payment references a billing cycle for a removed member - ignore ignore_payment(transaction, log_user, "no member") num_nomember += 1 except BillingCycle.DoesNotExist: # Payment references a legacy billing cycle - ignore payment ignore_payment(transaction, log_user, "legacy payment") num_nocycle += 1 except Payment.DoesNotExist: if not cycle.is_paid: logger.warning( "No transaction found for id: %s, member: %s year: %s. Marking as paid anyway" % (transaction, mid, year)) mark_cycle_paid(cycle, log_user, "Paid by a legacy payment (before 2010)") num_nopayment += 1 num_notattached = num_notattached + 1 logger.info( "Processed %s payments, attached %s payments, total %.2f EUR. Unidentified payments: %s" % (num_attached + num_notattached, num_attached, sum_attached, num_notattached)) logger.info( "No members: %s, no cycle: %s, no payment in db: %s, already attached to a cycle: %s" % (num_nomember, num_nocycle, num_nopayment, num_old))
def alias_edit(request, id, template_name='membership/entity_edit.html'): alias = get_object_or_404(Alias, id=id) class Form(ModelForm): class Meta: model = Alias fields = '__all__' owner = ModelChoiceField( queryset=Membership.objects.filter(pk=alias.owner.id), empty_label=None) @staticmethod def clean_name(): return alias.name @staticmethod def clean_owner(): return alias.owner def disable_fields(self): self.fields['name'].required = False self.fields['name'].widget.attrs['readonly'] = 'readonly' self.fields['owner'].required = False self.fields['owner'].widget.attrs['readonly'] = 'readonly' if request.method == 'POST': form = Form(request.POST, instance=alias) before = model_to_dict(alias) form.disable_fields() if form.is_valid(): form.save() after = model_to_dict(alias) log_change(alias, request.user, before, after) return redirect( 'alias_edit', id) # form stays as POST otherwise if someone refreshes else: form = Form(instance=alias) form.disable_fields() logentries = bake_log_entries(alias.logs.all()) return render_to_response(template_name, { 'form': form, 'alias': alias, 'logentries': logentries }, context_instance=RequestContext(request))
def process_csv(filename): """Actual CSV file processing logic """ num_attached = num_notattached = 0 sum_attached = sum_notattached = 0 num_nomember = num_nopayment = num_nocycle = num_old = 0 log_user = User.objects.get(id=1) with open(filename, 'r') as f: reader = csv.reader(f) for row in reader: (mid, year, date, reference, transaction) = row try: membership = Membership.objects.get(id=int(mid)) cycle = find_cycle(membership, year) payment = Payment.objects.get(transaction_id=transaction) if payment.billingcycle: # Already assigned, mark cycle as paid if payment.billingcycle != cycle: mark_cycle_paid(cycle, log_user, "One payment for several billing cycles") num_old += 1 continue payment.attach_to_cycle(cycle) log_change(payment, log_user, change_message="Attached by manual_matches") num_attached += 1 sum_attached += payment.amount continue except Membership.DoesNotExist: logger.warning("Membership %s not found. transaction id: %s" % (mid, transaction)) # Payment references a billing cycle for a removed member - ignore ignore_payment(transaction, log_user, "no member") num_nomember += 1 except BillingCycle.DoesNotExist: # Payment references a legacy billing cycle - ignore payment ignore_payment(transaction, log_user, "legacy payment") num_nocycle += 1 except Payment.DoesNotExist: if not cycle.is_paid: logger.warning("No transaction found for id: %s, member: %s year: %s. Marking as paid anyway" % (transaction, mid, year)) mark_cycle_paid(cycle, log_user, "Paid by a legacy payment (before 2010)") num_nopayment += 1 num_notattached = num_notattached + 1 logger.info("Processed %s payments, attached %s payments, total %.2f EUR. Unidentified payments: %s" % (num_attached + num_notattached, num_attached, sum_attached, num_notattached)) logger.info("No members: %s, no cycle: %s, no payment in db: %s, already attached to a cycle: %s" % (num_nomember, num_nocycle, num_nopayment, num_old))
def attach_payment_to_cycle(payment): """ Outside of this module, this function is mainly used by generate_test_data.py. """ if payment.ignore == True or payment.billingcycle != None: raise Exception("Unexpected function call. This shouldn't happen.") reference = payment.reference_number cycle = BillingCycle.objects.get(reference_number=reference) if cycle.is_paid == False or cycle.amount_paid() < cycle.sum: payment.attach_to_cycle(cycle) else: # Don't attach a payment to a cycle with enough payments payment.comment = _('duplicate payment') log_user = User.objects.get(id=1) log_change(payment, log_user, change_message="Payment not attached due to duplicate payment") payment.save() return None return cycle
def alias_edit(request, id, template_name='membership/entity_edit.html'): alias = get_object_or_404(Alias, id=id) class Form(ModelForm): class Meta: model = Alias fields = '__all__' owner = ModelChoiceField(queryset=Membership.objects.filter(pk=alias.owner.id), empty_label=None) @staticmethod def clean_name(): return alias.name @staticmethod def clean_owner(): return alias.owner def disable_fields(self): self.fields['name'].required = False self.fields['name'].widget.attrs['readonly'] = 'readonly' self.fields['owner'].required = False self.fields['owner'].widget.attrs['readonly'] = 'readonly' if request.method == 'POST': form = Form(request.POST, instance=alias) before = model_to_dict(alias) form.disable_fields() if form.is_valid(): form.save() after = model_to_dict(alias) log_change(alias, request.user, before, after) return redirect('alias_edit', id) # form stays as POST otherwise if someone refreshes else: form = Form(instance=alias) form.disable_fields() logentries = bake_log_entries(alias.logs.all()) return render_to_response(template_name, {'form': form, 'alias': alias, 'logentries': logentries}, context_instance=RequestContext(request))
def mark_cycle_paid(cycle, log_user, reason): if not cycle.is_paid: cycle.is_paid = True cycle.save() log_change(cycle, log_user, change_message=reason)
def create_member(mdata, logins): # legacy fields # ['application_id', 'sendinfo', 'memberclass', 'applicationtime', 'sms', # 'id', 'email', 'website', 'publicwebsite', 'lastname', 'phone', # 'firstnames', 'address', 'nationality', 'post', 'removed', 'publicname', # 'name', 'mobile', 'residence', 'time', 'publicemail', 'period_start', # 'period_end'] # TODO: latest billing period start date? post_index = mdata['post'].find(' ') postcode = mdata['post'][:post_index] postoffice = mdata['post'][post_index+1:] d = { 'street_address' : mdata['address'], 'postal_code' : postcode, 'post_office' : postoffice, 'country' : mdata['nationality'], 'phone' : mdata['phone'].replace(" ", "").replace("-", ""), 'sms' : mdata['sms'].replace(" ", "").replace("-", ""), 'email' : mdata['email'].strip(" "), 'homepage' : mdata['website'].strip(" "), 'first_name' : mdata['name'].strip(" "), 'given_names' : mdata['firstnames'].strip(" "), 'last_name' : mdata['lastname'].strip(" "), # mdata['application_id'], # mdata['sendinfo'], } # Hide non-public websites if not mdata['publicwebsite']: d['homepage'] = "" if not mdata['memberclass']: mtype = 'P' print >> sys.stderr, "# Member type missing for member %d" % mdata['id'] elif mdata['memberclass'] == 'member': mtype = 'P' elif mdata['memberclass'] == 'supporting': mtype = 'S' elif mdata['memberclass'] == 'organization': mtype = 'O' elif mdata['memberclass'] == 'honorary': mtype = 'H' else: print >> sys.stderr, "! Not importing, member class unknown for member %d" % mdata['id'] return False contact = Contact(**d) contact.save() if mtype == 'O': membership = Membership(id=mdata['id'], type=mtype, status='A', created=datetime.utcfromtimestamp(mdata['time']), approved=datetime.utcfromtimestamp(mdata['time']), organization=contact, nationality=mdata['nationality'], municipality=mdata['residence'], extra_info='Imported from legacy', public_memberlist=bool(mdata['publicname'])) else: membership = Membership(id=mdata['id'], type=mtype, status='A', created=datetime.utcfromtimestamp(mdata['time']), approved=datetime.utcfromtimestamp(mdata['time']), person=contact, nationality=mdata['nationality'], municipality=mdata['residence'], extra_info='Imported from legacy', public_memberlist=bool(mdata['publicname'])) logger.info("Member %s imported from legacy database." % (unicode(contact))) membership.save() # Create a period only if there already is one previously. Else let # makebills create one. if mdata.has_key('period_start'): billing_cycle = BillingCycle(membership=membership, is_paid=False, start=datetime.strptime(mdata['period_start'], "%Y-%m-%d %H:%M:%S"), end=datetime.strptime(mdata['period_end'], "%Y-%m-%d %H:%M:%S")+timedelta(days=1)) billing_cycle.save() bill = Bill(billingcycle=billing_cycle) bill.save() # Due to auto_now_add, need to save first before changing bill.created=datetime.strptime(mdata['bill_creation'], "%Y-%m-%d %H:%M:%S") bill.due_date=datetime.strptime(mdata['bill_dueday'], "%Y-%m-%d %H:%M:%S") bill.save() for alias in mdata['aliases']: if alias in logins: a = Alias(owner=membership, name=alias, account=True, created=membership.created) else: a = Alias(owner=membership, name=alias, account=False, created=membership.created) a.save() account_alias_count = Alias.objects.filter(owner=a.owner, account=True).count() if account_alias_count > 1: logger.warning("%i account aliases for %s" % (account_alias_count, a.owner)) log_change(membership, user, change_message="Imported into system") return True