Ejemplo n.º 1
0
    def parse(self):
        content = self.content
        f = StringIO(content)
        reader = DictReaderStrip(f, delimiter=',')
        transactions = []
        for row in reader:
            print("Importing {} at {}".format(row['商品'], row['交易时间']))
            meta = {}
            time = dateparser.parse(row['交易时间'])
            meta['wechat_trade_no'] = row['交易单号']
            meta['trade_time'] = row['交易时间']
            meta['timestamp'] = str(time.timestamp()).replace('.0', '')
            account = get_account_by_guess(row['交易对方'], row['商品'], time)
            # flag = "*"
            amount_string = row['金额(元)'].replace('¥', '')
            amount = float(amount_string)

            if row['商户单号'] != '/':
                meta['shop_trade_no'] = row['商户单号']

            if row['备注'] != '/':
                meta['note'] = row['备注']

            meta = data.new_metadata(
                'beancount/core/testing.beancount',
                12345,
                meta
            )
            entry = Transaction(
                meta,
                date(time.year, time.month, time.day),
                '*',
                row['交易对方'],
                row['商品'],
                data.EMPTY_SET,
                data.EMPTY_SET, []
            )

            status = row['当前状态']

            if status == '支付成功' or status == '朋友已收钱' or status == '已全额退款' or '已退款' in status:
                if '转入零钱通' in row['交易类型']:
                    entry = entry._replace(payee='')
                    entry = entry._replace(narration='转入零钱通')
                    data.create_simple_posting(
                        entry, Account零钱通, amount_string, 'CNY')
                else:
                    if '微信红包' in row['交易类型']:
                        account = Account支出红包
                        if entry.narration == '/':
                            entry = entry._replace(narration=row['交易类型'])
                    else:
                        account = get_account_by_guess(
                            row['交易对方'], row['商品'], time)
                    # if account == "Unknown":
                    #	entry = replace_flag(entry, '!')
                    if status == '已全额退款':
                        amount_string = '-' + amount_string
                    data.create_simple_posting(
                        entry, account, amount_string, 'CNY')
                data.create_simple_posting(
                    entry, accounts[row['支付方式']], None, None)
            elif row['当前状态'] == '已存入零钱':
                if '微信红包' in row['交易类型']:
                    if entry.narration == '/':
                        entry = entry._replace(narration=row['交易类型'])
                    data.create_simple_posting(entry, Account收入红包, None, 'CNY')
                else:
                    income = get_income_account_by_guess(
                        row['交易对方'], row['商品'], time)
                    if income == 'Income:Unknown':
                        entry = replace_flag(entry, '!')
                    data.create_simple_posting(entry, income, None, 'CNY')
                data.create_simple_posting(
                    entry, Account余额, amount_string, 'CNY')
            else:
                print('Unknown row', row)

            #b = printer.format_entry(entry)
            # print(b)
            if not self.deduplicate.find_duplicate(entry, amount, 'wechat_trade_no'):
                transactions.append(entry)

        self.deduplicate.apply_beans()
        return transactions
Ejemplo n.º 2
0
	def parse(self):
		content = self.content
		f = StringIO(content)
		reader = DictReaderStrip(f, delimiter=',')
		transactions = []
		for row in reader:
			print("Importing {} at {}".format(row['商品名称'], row['最近修改时间']))
			meta = {}
			time = dateparser.parse(row['最近修改时间'])
			meta['alipay_trade_no'] = row['交易号']
			meta['trade_time'] = row['最近修改时间']
			meta['timestamp'] = str(time.timestamp()).replace('.0', '')
			account = get_account_by_guess(row['交易对方'], row['商品名称'], time)
			flag = "*"
			amount = float(row['金额(元)'])
			if account == "Unknown":
				flag = "!"

			if row['备注'] != '':
				meta['note'] = row['备注']

			if row['商家订单号'] != '':
				meta['shop_trade_no'] = row['商家订单号']

			meta = data.new_metadata(
				'beancount/core/testing.beancount',
				12345,
				meta
			)
			entry = Transaction(
				meta,
				date(time.year, time.month, time.day),
				flag, 
				row['交易对方'],
				row['商品名称'],
				data.EMPTY_SET,
				data.EMPTY_SET, []
			)
			data.create_simple_posting(entry, account, row['金额(元)'], 'CNY')
			if row['资金状态'] == '已支出':
				data.create_simple_posting(entry, Account支付宝, None, None)
				amount = -amount
			elif row['资金状态'] == '资金转移':
				data.create_simple_posting(entry, Account支付宝, None, None)
			elif row['资金状态'] == '已收入':
				income = get_income_account_by_guess(row['交易对方'], row['商品名称'], time)
				if income == 'Income:Unknown':
					entry = entry._replace(flag = '!')
				data.create_simple_posting(entry, income, None, None)
			else:
				print('Unknown status')
				print(row)

			if (row['服务费(元)'] != '0.00'):
				data.create_simple_posting(entry, 'Expenses:Fee', row['服务费(元)'], 'CNY')
			
			#b = printer.format_entry(entry)
			#print(b)
			if not self.deduplicate.find_duplicate(entry, amount):
				transactions.append(entry)

		self.deduplicate.apply_beans()
		return transactions
Ejemplo n.º 3
0
def test_insert_entry_transaction(tmp_path) -> None:
    file_content = dedent("""\
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD
        """)
    samplefile = tmp_path / "example.beancount"
    samplefile.write_text(file_content)

    postings = [
        Posting(
            "Liabilities:US:Chase:Slate",
            A("-10.00 USD"),
            None,
            None,
            None,
            None,
        ),
        Posting("Expenses:Food", A("10.00 USD"), None, None, None, None),
    ]

    transaction = Transaction(
        {},
        date(2016, 1, 1),
        "*",
        "new payee",
        "narr",
        None,
        None,
        postings,
    )

    # Test insertion without "insert-entry" options.
    insert_entry(transaction, str(samplefile), [], 61)
    assert samplefile.read_text("utf-8") == dedent("""\
        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD
        """)

    # Verify that InsertEntryOptions with dates greater or equal than the
    # transaction dates are ignored.
    options = [
        InsertEntryOption(
            date(2015, 1, 1),
            re.compile(".*:Food"),
            str(samplefile),
            1,
        ),
        InsertEntryOption(
            date(2015, 1, 2),
            re.compile(".*:FOOO"),
            str(samplefile),
            1,
        ),
        InsertEntryOption(
            date(2017, 1, 1),
            re.compile(".*:Food"),
            str(samplefile),
            6,
        ),
    ]
    new_options = insert_entry(transaction._replace(narration="narr1"),
                               str(samplefile), options, 61)
    assert new_options[0].lineno == 5
    assert new_options[1].lineno == 5
    assert new_options[2].lineno == 10
    assert samplefile.read_text("utf-8") == dedent("""\
        2016-01-01 * "new payee" "narr1"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD
        """)

    # Verify that previous postings are matched against InsertEntryOptions when
    # the last posting doesn't match.
    options = [
        InsertEntryOption(
            date(2015, 1, 1),
            re.compile(".*:Slate"),
            str(samplefile),
            5,
        ),
        InsertEntryOption(
            date(2015, 1, 2),
            re.compile(".*:FOOO"),
            str(samplefile),
            1,
        ),
    ]
    transaction = transaction._replace(narration="narr2")
    new_options = insert_entry(transaction, str(samplefile), options, 61)
    assert new_options[0].lineno == 9
    assert new_options[1].lineno == 1
    assert samplefile.read_text("utf-8") == dedent("""\
        2016-01-01 * "new payee" "narr1"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-01-01 * "new payee" "narr2"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD
        """)

    # Verify that preference is given to InsertEntryOptions with later dates in
    # case several of them match a posting.
    options = [
        InsertEntryOption(
            date(2015, 1, 1),
            re.compile(".*:Food"),
            str(samplefile),
            5,
        ),
        InsertEntryOption(
            date(2015, 1, 2),
            re.compile(".*:Food"),
            str(samplefile),
            1,
        ),
    ]
    transaction = transaction._replace(narration="narr3")
    insert_entry(transaction, str(samplefile), options, 61)
    assert samplefile.read_text("utf-8") == dedent("""\
        2016-01-01 * "new payee" "narr3"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-01-01 * "new payee" "narr1"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-01-01 * "new payee" "narr2"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD

        2016-02-26 * "Uncle Boons" "Eating out alone"
            Liabilities:US:Chase:Slate                       -24.84 USD
            Expenses:Food:Restaurant                          24.84 USD

        2016-01-01 * "new payee" "narr"
          Liabilities:US:Chase:Slate                         -10.00 USD
          Expenses:Food                                       10.00 USD
        """)
Ejemplo n.º 4
0
    def modify_entry(
            self,
            entry: data.Transaction,
            match_values: dict,
            flag_to_done=True):
        """takes an Entry and a dict of values we parsed from the Entry
        """

        # Pre-process match_value?
        for sr in self.set_rules:

            if sr.directive == 'transaction':
                # Should Possible Eval the Value?
                if sr.meta_key:
                    # Meta Key is inserted
                    meta = dict(entry.meta)
                    meta[sr.meta_key] = sr.value
                    entry = entry._replace(meta=meta)
                else:
                    value = sr.value
                    if sr.parameter in ('links', 'tags'):
                        current:set = getattr(entry, sr.parameter, set()) or set()
                        current.add(value)
                        value = current

                    entry = entry._replace(**{sr.parameter: value})

            elif sr.directive == 'posting':
                postings = []
                for posting in entry.postings:
                    if posting.flag == '!':
                        if sr.meta_key:
                            meta = dict(posting.meta)
                            meta[sr.meta_key] = sr.value
                            posting = posting._replace(
                                meta=meta
                            )
                        elif sr.value is not None:
                            posting = posting._replace(**{
                                sr.parameter: sr.value
                            })
                        else:
                            logger.warning(f"Invalid directive to Set {sr.parameter} to {sr.value} on {posting} for {entry}")
                            logger.warning(f"{self}")
                        logger.debug(f"New POSTING: {posting}")
                    postings.append(posting)

                entry = entry._replace(postings=postings)

            for field, value in match_values.items():
                # We allow <payee> and <meta_tagname> in match-groups
                if field == "payee" and not entry.payee:
                    entry = entry._replace(payee=value.title())  # Propercase
                if field.startswith('meta_'):
                    meta_name = field[5:]
                    entry.meta[meta_name] = value

        if flag_to_done:
            # Set all ! -> *
            postings = []
            for posting in entry.postings:
                if posting.flag == '!':
                    posting = posting._replace(flag='')
                postings.append(posting)
            entry = entry._replace(postings=postings, flag='*')

        return entry