class TestJournalEntry(TestCase): """ JournalEntry model tests """ def setUp(self): self.journalEntry = JournalEntry() self.journalEntry.title = "Test title" self.journalEntry.author = testUser self.journalEntry.show_on_main = False def test_import(self): """ Should import module """ self.assertIsNotNone(JournalEntry) self.assertIsNotNone(get_group_journals) def test_unicode(self): """ Should return unicode value """ self.assertIsNotNone(unicode(self.journalEntry)) self.assertTrue(unicode(self.journalEntry).endswith( self.journalEntry.title)) @skip def test_save_and_retrieve(self): """ Should save and retrieve """ self.assertEqual( 0, JournalEntry.objects.all().count(), "Should be empty") self.journalEntry.save() allEntries = JournalEntry.objects.all() self.assertEqual(1, allEntries.count(), "Should have 1 entry") entry = allEntries[0] self.assertIsInstance(entry, JournalEntry, "Should be an instance of JournalEntry") # Make sure the correct values have been saved self.assertEqual(entry.title, self.journalEntry.title, "Should have same title") self.assertEqual(entry.author.name, self.journalEntry.author.name, "Should have same authors") self.assertEqual(entry.show_on_main, False) @skip def test_get_absolute_url(self): self.assertIsNotNone(self.journalEntry.get_absolute_url()) def test_has_plural(self): self.assertIsNotNone(JournalEntry._meta.verbose_name_plural)
class TestJournalEntry(TestCase): """ JournalEntry model tests """ def setUp(self): self.journalEntry = JournalEntry() self.journalEntry.title = "Test title" self.journalEntry.author = testUser self.journalEntry.show_on_main = False def test_import(self): """ Should import module """ self.assertIsNotNone(JournalEntry) self.assertIsNotNone(get_group_journals) def test_unicode(self): """ Should return unicode value """ self.assertIsNotNone(unicode(self.journalEntry)) self.assertTrue(unicode(self.journalEntry).endswith(self.journalEntry.title)) @skip("TODO: Fix this test") def test_save_and_retrieve(self): """ Should save and retrieve """ self.assertEqual(0, JournalEntry.objects.all().count(), "Should be empty") self.journalEntry.save() allEntries = JournalEntry.objects.all() self.assertEqual(1, allEntries.count(), "Should have 1 entry") entry = allEntries[0] self.assertIsInstance(entry, JournalEntry, "Should be an instance of JournalEntry") # Make sure the correct values have been saved self.assertEqual(entry.title, self.journalEntry.title, "Should have same title") self.assertEqual(entry.author.name, self.journalEntry.author.name, "Should have same authors") self.assertEqual(entry.show_on_main, False) @skip("TODO") def test_get_absolute_url(self): self.assertIsNotNone(self.journalEntry.get_absolute_url()) def test_has_plural(self): self.assertIsNotNone(JournalEntry._meta.verbose_name_plural)
def new(request, year): year = int(year) # Default the date to the same date as the last entry for this year, # provided one exists. Otherwise, just the start of the year. try: lastentry = JournalEntry.objects.filter(year=year).order_by('-date')[0] d = lastentry.date except IndexError: d = date(year,1,1) year = get_object_or_404(Year, year=year) highseq = JournalEntry.objects.filter(year=year).aggregate(Max('seq'))['seq__max'] if highseq is None: highseq = 0 entry = JournalEntry(year=year, seq=highseq+1, date=d, closed=False) entry.save() # Disable any search query to make sure we can actually see # the record we've just created. _setup_search(request, '') return HttpResponseRedirect('/accounting/e/%s/' % entry.pk)
def webpay_run(name, payment_pk, *args, **kwargs): """Runs a Webpay binary within a preconfigured environment. Before running the binary, this context manager recreates the directories and files in /tmp that the binary needs to run correctly, as if it were sitting in an standalone web server. Yields a subprocess.Popen instance with an open pipe to stdin and stdout. After running the binary, log and journal entries are captured and then temporary files are removed. Args: name: A string, basename of the binary as is found in assets_dir. payment_pk: An integer, primary key for the related payment. This is needed to associate the logs with their payment. *args: Extra positional arguments are appended to the command line before execution. Example: >>> webpay_run('tbk_bp_resultado.cgi', 3958) as cgi: output, _ = cgi.communicate("TBK_MONTO=384800&...\n") do_something_with(output) WARNING: Always use Popen with communicate() method when using PIPE or there will be deadlocks. """ from pprint import pprint # prepare the configuration files assets_dir = PaymentProcessor.get_backend_setting('WEBPAY_DOCS') tbk_config = PaymentProcessor.get_tbk_config(kwargs.get('request'), payment_pk, 'CLP') # FIXME tbk_param = PaymentProcessor.get_tbk_param() tbk_trace = PaymentProcessor.get_tbk_trace() # temp_dir = mkdtemp() cgi_path = os.path.join(assets_dir, name) # temp_cgi_path = os.path.join(assets_dir, name) datos_path = os.path.join(assets_dir, 'datos') # os.mkdir(datos_path) # with open(os.path.join(datos_path, 'tbk_config.dat'), 'w') as f: # pprint("TBK_CONFIG: %s" % tbk_config) # pprint('------------------------------------------') # f.write(tbk_config) # with open(os.path.join(datos_path, 'tbk_param.txt'), 'w') as f: # f.write(tbk_param) # with open(os.path.join(datos_path, 'tbk_trace.dat'), 'w') as f: # f.write(tbk_trace) # prepare the public and private keys maestros_path = os.path.join(assets_dir, 'maestros') public_key, private_key = PaymentProcessor.get_keys() # os.mkdir(maestros_path) # with open(os.path.join(maestros_path, 'tbk_public_key.pem'), 'w') as f: # f.write(public_key) # with open(os.path.join(maestros_path, 'privada.pem'), 'w') as f: # f.write(private_key) # prepare the log directory log_path = os.path.join(assets_dir, 'log') # os.mkdir(log_path) # copy the binary to the temp dir and make it executable # copyfile(cgi_path, temp_cgi_path) # os.chmod(cgi_path, S_IEXEC) yield Popen([sys.executable, cgi_path] + list(args), stdin=PIPE, stdout=PIPE) # capture the logs try: from getpaid.models import Payment payment = Payment.objects.get(pk=payment_pk) for event_log in glob.glob(os.path.join(log_path, 'TBK_EVN*')): with open(event_log, 'r') as f: for line in map(str.strip, f.readlines()): pprint("TBK_ENV: %s" % line) from models import LogEntry entry = LogEntry.from_line(line=line, payment=payment) entry.save() pprint('------------------------------------------') for journal_log in glob.glob( os.path.join(log_path, 'tbk_bitacora_TR_NORMAL*')): st = os.stat(journal_log) date = datetime.date.fromtimestamp(st.st_mtime) with open(journal_log, 'r') as f: for line in map(str.strip, f.readlines()): pprint("TBK_BITACORA: %s" % line) from models import JournalEntry entry = JournalEntry(date=date, body=line, payment=payment) entry.save() pprint('------------------------------------------') except Payment.DoesNotExist: pass
def webpay_run(name, payment_pk, *args, **kwargs): """Runs a Webpay binary within a preconfigured environment. Before running the binary, this context manager recreates the directories and files in /tmp that the binary needs to run correctly, as if it were sitting in an standalone web server. Yields a subprocess.Popen instance with an open pipe to stdin and stdout. After running the binary, log and journal entries are captured and then temporary files are removed. Args: name: A string, basename of the binary as is found in assets_dir. payment_pk: An integer, primary key for the related payment. This is needed to associate the logs with their payment. *args: Extra positional arguments are appended to the command line before execution. Example: >>> webpay_run('tbk_bp_resultado.cgi', 3958) as cgi: output, _ = cgi.communicate("TBK_MONTO=384800&...\n") do_something_with(output) WARNING: Always use Popen with communicate() method when using PIPE or there will be deadlocks. """ from pprint import pprint # prepare the configuration files assets_dir = PaymentProcessor.get_backend_setting('ASSETS_DIR') tbk_config = PaymentProcessor.get_tbk_config(payment_pk, 'CLP') # FIXME tbk_param = PaymentProcessor.get_tbk_param() tbk_trace = PaymentProcessor.get_tbk_trace() temp_dir = mkdtemp() cgi_path = os.path.join(assets_dir, name) temp_cgi_path = os.path.join(temp_dir, name) datos_path = os.path.join(temp_dir, 'datos') os.mkdir(datos_path) with open(os.path.join(datos_path, 'tbk_config.dat'), 'w') as f: pprint("TBK_CONFIG: %s" % tbk_config) pprint('------------------------------------------') f.write(tbk_config) with open(os.path.join(datos_path, 'tbk_param.txt'), 'w') as f: f.write(tbk_param) with open(os.path.join(datos_path, 'tbk_trace.dat'), 'w') as f: f.write(tbk_trace) # prepare the public and private keys maestros_path = os.path.join(temp_dir, 'maestros') public_key, private_key = PaymentProcessor.get_keys() os.mkdir(maestros_path) with open(os.path.join(maestros_path, 'tbk_public_key.pem'), 'w') as f: f.write(public_key) with open(os.path.join(maestros_path, 'privada.pem'), 'w') as f: f.write(private_key) # prepare the log directory log_path = os.path.join(temp_dir, 'log') os.mkdir(log_path) # copy the binary to the temp dir and make it executable copyfile(cgi_path, temp_cgi_path) os.chmod(temp_cgi_path, S_IEXEC) yield Popen([temp_cgi_path] + list(args), stdin=PIPE, stdout=PIPE) # capture the logs try: from getpaid.models import Payment payment = Payment.objects.get(pk=payment_pk) for event_log in glob.glob(os.path.join(log_path, 'TBK_EVN*')): with open(event_log, 'r') as f: for line in map(str.strip, f.readlines()): pprint("TBK_ENV: %s" % line) from models import LogEntry entry = LogEntry.from_line(line=line, payment=payment) entry.save() pprint('------------------------------------------') for journal_log in glob.glob(os.path.join(log_path, 'tbk_bitacora_TR_NORMAL*')): st = os.stat(journal_log) date = datetime.date.fromtimestamp(st.st_mtime) with open(journal_log, 'r') as f: for line in map(str.strip, f.readlines()): pprint("TBK_BITACORA: %s" % line) from models import JournalEntry entry = JournalEntry(date=date, body=line, payment=payment) entry.save() pprint('------------------------------------------') except Payment.DoesNotExist: pass # clean up rmtree(temp_dir)
def create_accounting_entry(date, items, leaveopen=False, urllist=None): # items must be an array of tuples in the format: # (accountnumber, descriptiontext, amount, objectname) # Positive amounts indicate debit, negative amounts indicate credit. # objects are referenced by *named* and looked up internally here. # Entries must be balanced unless leaveopen is set to True # Any urls listed in urllist must exist and be correct, no verification # is done. if not settings.ENABLE_AUTO_ACCOUNTING: return sid = transaction.savepoint() try: # Start by some simple validation for r in items: if r[2] == 0: raise AccountingException("Submitted accounting journal entry has a zero sum entry!") if Decimal(r[2]).as_tuple().exponent < -2: raise AccountingException("Submitted accounting journal entry has items that are not rounded off to two decimal points!") debitsum = sum([r[2] for r in items if r[2] > 0]) creditsum = -sum([r[2] for r in items if r[2] < 0]) if debitsum != creditsum and not leaveopen: raise AccountingException("Submitted accounting journal entry is not balanced!") try: year = Year.objects.get(year=date.year) except Year.DoesNotExist: raise AccountingException("Year %s does not exist in the accounting system!" % date.year) if not year.isopen: raise AccountingException("Year %s is not open for new entries!" % date.year) seq = JournalEntry.objects.filter(year=year).aggregate(Max('seq'))['seq__max'] if seq is None: seq = 0 # We assume the rest is correct and start building the db entries, # since we'll just roll it back if referenced data is missing. entry = JournalEntry(year=year, seq=seq+1, date=date, closed=False) entry.save() for accountnum, description, amount, objectname in items: try: account = Account.objects.get(num=accountnum) if objectname: obj = Object.objects.get(name=objectname) else: obj = None JournalItem(journal=entry, account=account, amount=amount, object=obj, description=description).save() except Account.DoesNotExist: raise AccountingException("Account %s does not exist!" % accountnum) except Object.DoesNotExist: raise AccountingException("Object %s does not exist!" % objectname) # If there are any URLs to attach, do so now if urllist: for url in urllist: JournalUrl(journal=entry, url=url).save() # All items saved correct. Close the entry if we have to. We verified # above that it's valid... if not leaveopen: entry.closed = True entry.save() # Ok, it seems it worked... transaction.savepoint_commit(sid) except: transaction.savepoint_rollback(sid) raise