Git Product home page Git Product logo

billy's People

Contributors

ajsharp avatar fangpenlin avatar mahmoudimus avatar mdrollette avatar mjallday avatar pnegahdar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

billy's Issues

Should amounts be in cents?

curl https://billing.balancedpayments.com/v1/plans \
    -X POST \
    -u 6w9KwCPCmCQJpEYgCCtjaPmbLNQSavv5sX4mCZ9Sf6pb: \
    -d "plan_type=charge" \
    -d "amount=5" \
    -d "frequency=monthly"
{
    "guid": "PL97ZvyeA4wzM3WUyEG8xwps",
    "company_guid": "CPMM8C8Uhkt4pDeJ8oqJu8Nj",
    "plan_type": "charge",
    "interval": 1,
    "amount": "5.00",
    "frequency": "monthly",
    "deleted": false,
    "created_at": "2013-10-02T05:48:26.210843",
    "updated_at": "2013-10-02T05:48:26.210843"
}

How does retry logic work?

One of the things that we've seen with companies that have recurring billing or delayed invoicing is a higher than normal rate of Soft Failures when charging a card. A Soft Failure is a card declination where you can retry later and possibly have the card approved.

Here are a few examples:

  1. Insufficient funds. The card holder may pay off their balance the next day, which means you can now charge the card.
  2. Blocked card. I had my card blocked as a result of making a purchase in Spain. I received an email from GitHub that my recurring payment failed. I called my bank and had the block removed explaining I was in fact in Spain. GitHub automatically retried, and the charge went through
  3. The recurring charge itself is flagged. The card holder will receive notification from their bank verifying the charge. Attempting the charge again will cause a success

How will this be handled by billy?

Adjustments

Often at Balanced, we need to make ad-hoc adjustments to invoices.

This can be done as part of an initial creation of an invoice or after an invoice has failed and is about to be resubmitted.

An adjustment can be for any arbitrary amount, both positive or negative and will have a string field associated with it describing the reason for the adjustment.

Can Billy handle this?

Implement subscription canceling and plan deleting

Subscription canceling and plan deleting are not implemented, yet.

I think when we delete a plan, all subscriptions to it should also be canceled.

The refunding (in processor and process_transactions script) is also not implemented. So, if we want to implement prorated_refund, we need to implement refunding first.

Define operations and usage scenarios clearly

@mahmoudimus

As mentioned section 4 in #24, I think we need some definitions about what kind of operations this service should provide and what kind of scenarios to use them. I think one of reasons I have no idea how to contribute on this project is that I cannot find documents about this in the project. What is a plan, what is subscription and so on.

I see you have wrote

import billy

# create the goat plan to bill every 3 months.

billy.Plan.create(
    amount=100,
    description='the goat - silver',
    trial_period=None,
    frequency=billy.Frequency.MONTHLY,
    interval=3
)

in readme file. I feel that could be helpful as it provides a scenario how it would work. But still lack some important details (who to charge, what kind of method should be used with balanced API? what is the trial period here?). I need your input. Could you envision more about how this service should be used?

How to deal database failure with Balanced API calls?

I would like to ask a question about how can I deal with database transaction failure with Balanced API calls?

For example, here I am processing a single transaction generated from a subscription

# create a transaction record in local database
tid = create_transaction(
    amount=100,
    payment_uri='/v1/credit_card/xxx'
)

# try to debit with balanced
transaction = get_transaction(tid)
debit_id = balanced.debit(transaction.payment_uri)

# NOTICE: When following update fails, we have a big trouble, 
# the charging may already done, but we have no idea (no record) about that
# the system will certainly charge the customer again later

# update transaction record, we made a success debit
update_transaction(
    tid=tid,
    status='done',
    debit_id=debit_id,
)

This could work fine if everything goes well, however, when a crash or something bad happens during processing this, let's say, the final update_transaction is not done successfully. In this case, there is no transaction finish record in the database, billy system will think this transaction is not finish yet, it will try to charge it again when the system goes back online.

The way PayPal deals with this is that user needs to create a profile before they do a transaction like this

# make sure we won't duplicate transaction
tx = get_transaction()
if tx is not None:
    pp_tx = paypal.get_profile(tx.profile_id)
    if pp_tx.status == 'Paid':
        update_transaction(tx.id, status='done')
        return

profile = paypal.create_profile(...)
create_transaction(profile_id=profile.id)

result = paypal.start_recurring_payment(...)
if result.status == 'Paid':
    update_transaction(tx.id, status='done')

As you can see, we can store the profile id in database before we do a real transaction. We can then check before doing a transaction, to make sure it is not already done.

With balanced, it appears there is only one step to do a transaction. A possible approach to workaround this is to assign a billy generated transaction id to balanced transaction. And we can get previous transaction record back with this id before we try to do a transaction again.

The code would look like this

# make sure we won't duplicate transaction
tx = get_transaction()
if tx is not None:
    bp_tx = balanced.get_transaction(tx.id)
    if bp_tx.status == 'Paid':
        update_transaction(tx.id, status='done')
        return

tx = create_transaction(...)
balanced.debit(tx.payment_uri)

update_transaction(tx.id, status='done')

I am not very familiar with the API, I see there is a meta field I can set some of my key-value data to it, but is there a way to retrieve a record by the ID or data I set previously? Or are there other ways to workaround this?

Create a setup script

I just cloned the repo and tried to run the tests.

I needed to manually install the nose test runner and now I'm getting errors about the db and user not existing.

It would be great if I could run something like ./scripts/db-recreate-test which would ensure those exist for me.

Have a recurring bank debit task that executes on configurable business rules.

Some marketplaces use Balanced mainly for next-day ACH.

If you're also performing card processing with Balanced, you will always carry an escrow from the card transactions. If you're only using Balanced to pay customers, they you have to fund the yourself. This means the escrow can run out, which will cause transactions to fail.

Balanced should add the ability to specify, in the dashboard, a minimum amount to maintain in escrow. If the escrow drops below that amount, Balanced will auto-debit to ensure there's no service interruption.

Build API Base

Build API layer on top of models using flask. Should be good man.

Limit failure times of a transaction

The way we process transactions periodically is like this

Yield transactions from subscriptions
Process transactions

We yield transactions for recurring charging/paying-out/refunding as transaction records in the database. The initial status is INIT, then we process them. If everything goes well, it should then transit into DONE status. However, when something goes wrong, it will go into RETRYING status, and we will try to process it again later.

Sometimes, the retrying transactions are just never going to be finished as something is wrong from very beginning, such as wrong balanced API given by user. In this case, it is only wasting time and resource to keep trying these transactions.

So, here I want to limit the maximum retry times for each transactions. After a specific retry times, a transaction shall transit into FAILED status.

The whole state transition would look like this:
billy_transaction_state_diagram

And a note here, as the branch is merged back, I want to keep the development traceable to everybody, so I will stop working on the master branch directly. I will try to create issues and corresponding branch and pull request. I will keep the master as stable as possible, so that everybody can work on it. Also, for pull requests, I think only the ones pass all unit tests and functional tests should be merged. I see youguys have pretty cool testing integration with Github for balanced-dashboard that indicates testing result for each commit. I don't know what it is, but I think we can do the same on billy.

Implement record listing

Record listing is not implemented yet. For now, we only have transaction list for a company

/v1/transactions/

maybe it would be nice to have transaction listing for a subscription or for a plan and customer? Like

/v1/subscriptions/SUXXXXXX/transactions
/v1/plans/PLXXXXXX/transactions
/v1/customers/CUXXXXX/transactions

Maybe we should consider this with #40, see what kind of style we should use.

How can I run tests?

@pnegahdar

I am trying to work on billy project, however, I cannot get tests work. How can I run them correctly?

I tried nosetests on the mater branch, and basically everything failed

$ nosetests

EEEEEEEEEEEEEEEE
======================================================================
ERROR: Failure: InvalidRequestError (Table 'charge_subscription' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.)
----------------------------------------------------------------------
    (... omit ...)
----------------------------------------------------------------------
Ran 16 tests in 0.012s

FAILED (errors=16)

The complete dump: https://gist.github.com/victorlin/6204313

It appears that something goes wrong with import issue and table declarations. So, I tried my import fixed branch, and I get other tons of error

EEEEEEEEEEEEEEE
======================================================================
ERROR: Failure: ImportError (cannot import name sample_customer_2)
----------------------------------------------------------------------
    ( ... omit ...)
----------------------------------------------------------------------
Ran 15 tests in 0.563s

FAILED (errors=15)

The complete dump: https://gist.github.com/victorlin/6204321

None of tests passed, did I miss something? How do you run tests usually?

appears_on_statement_as parameter for Billy transactions

I've been unable to find a way to specify the appears_on_statement_as for Billy recurring transactions. I would think this parameter would exist when you create a plan.

Does this functionality already exist? If not, this would be a valuable enhancement.

Put micro-deposit verification logic into Billy

From a potential customer:

Before the ACH transfer, we need to verify account access. Like many sites, we are planning to do micro-deposits (ACH credit) for their account.

Can Balanced help us do micro-deposits to a customer's account?

It's not efficient for a customer to use Balanced for this if they won't also be using Balanced's ACH Debts functionality. Does it make sense or Billy to contain the logic for MDVs, so these customers can use Billy with another ACH provider?

Billy enhancement proposal

This project works fine, so far so good. However, the barrier for letting people getting work on this project is a little bit high, namely, technical debt should be reduced. I would like to do some major refactorying. Before we go into implementation, some goals to achieve are listed here to remind us.
#1. Documentation

We should write some documents. Developer could understand how to use this project, what are some classes and module for. Some comments in code could be helpful. For example, when you are using a dirty hack, it's better to write why you are doing this, and what kind of side effect it may have. Something might look like this

# NOTICE: this is a dirty hack to use foo module
# as xxx feature is not supported in foo version xx
# it's better to find a more clean way to do this
foo._dirty_hacky_call()

Also, when you left something unfinished or not sure what to do, you can leave a # TODO comment on it:

# TODO: get rid of the brute force and improve performance

High level document should also be added to make people understand the project easily. Such as some how-to-use-it API call example.

Here we demonstrate how to create a daily basis payout:

    api = billy.API(api_key='xxx')
    api.daily_payout(...)

Something like that.

Document is important, but do not overkill.
#2. Isolate data model from the table definition

Data model and business logic should be extracted from tables and put in some isolated classes. Do not expose too much SQLALchemy details to the client side (the web framework views). In this way, it is much easier to test, also, when we don't want to use another web framework, it is much easier to adopt. Or, when we are switching to a NO-SQL database, the data model in middle also do help. We don't need to rewrite the whole client-end code, the data model interface should remains almost the same, we only need to rewrite under layer database querying stuff. Some visual explanation would looks like this.

The original design

[SQLAlchemy tables with business logic] <-------- [Flask client-end code]

the new approach

[SQLAlchemy tables] <-------- [Business logic] <--------  [Flask client-end code]

#3. Use SQLIte as the default database storage

To make it as easier to test and deploy as possible, we should use SQLite as the default database storage. The way we use SQL should also be as standard as possible (do not use XX database only feature). In this way, developers who like to get involved can jump in and start hacking quickly without installing any database server on their machine. The testing suites can also be ran without any extra setups. Users can also even use SQLite as the database in production environment when it is really easy to get started.

When SQLite based operation is well tested and proved. Surely SQLAlchemy can support almost any other SQL database without too much effort.
#4. Define operations and usage scenarios clearly

I think it is necessary to define what kind of operation this service should provide and what kind of scenario they will be used. With those descriptions, we can then implement those feature correctly and understand when to use them. For example, Niko wants to charge protection fee weekly from Tony (ah.. what a badass). Then he can create a plan (or bill plan more clearly?) like this:

import billy

# create the goat plan to bill every 3 months.

billy.Plan.create(
    amount=100,
    description='weekly protection fee',
    trial_period=None,
    frequency=billy.Frequency.WEEKLY,
    interval=3
)

Otherwise, without clear blueprint in mind, people can hardly understand it.


Cannot recall some ideas passed my mind, will update this when they come back to me.

Metered invoicing support

Balanced internally has built its own (very simple) metered billing system to instrument our customer's use of the API.

We collect some statistics on their usage and at 0:00 UTC every day, we generate an invoice for that business day and then settle it.

I want to move this logic out of Balanced and into Billy. Ergo, Billy should support metered billing support and the Balanced dashboard should use Billy to display the invoices for our customers.

/cc @victorlin @mjallday @kleinsch

PyPI and clients

The name billy is already taken on PyPI.

Should we:

  • rename the project to billie?
  • Publish the project as pybilly?

Keep tests in good style

I had a glance on the test code, I think it needs some clean up. For example, import statements should not be put in the module level. In cases, some modules are missing, other tests can continue.

For example, this

import unittest

class TestSometing(unittest.TestCase):

    def test_xxx(self):
        import module1
        from my_module import do_some_thing
        do_some_thing()
        # ...

is better than

import unittest

import module1
from my_module import do_some_thing

class TestSometing(unittest.TestCase):

    def test_xxx(self):
        do_some_thing()
        # ...

For more guideline, please reference to this article:

http://docs.pylonsproject.org/en/latest/community/testing.html

It is Pyramid testing guideline, very neat practices to follow. Pyramid have 100% test coverage, these guys are proud of it.

Missing dependency

I created a new virtualenv and installed billy by running python setup.py develop && pip install -r requirements.txt

Next, I tried to run initialize_billy_db development.ini

| ~/code/balanced/billy @ mjallday-2  (billy)(master) 
| => initialize_billy_db development.ini
Traceback (most recent call last):
  File "/Users/marshall/.virtualenvs/billy/bin/initialize_billy_db", line 9, in <module>
    load_entry_point('billy==0.0.1', 'console_scripts', 'initialize_billy_db')()
  File "/Users/marshall/code/balanced/billy/billy/scripts/initializedb.py", line 27, in main
    settings = setup_database({}, **settings)
  File "/Users/marshall/code/balanced/billy/billy/models/__init__.py", line 18, in setup_database
    engine_from_config(settings, 'sqlalchemy.')
  File "/Users/marshall/.virtualenvs/billy/lib/python2.7/site-packages/SQLAlchemy-0.8.2-py2.7-macosx-10.8-x86_64.egg/sqlalchemy/engine/__init__.py", line 351, in engine_from_config
    return create_engine(url, **opts)
  File "/Users/marshall/.virtualenvs/billy/lib/python2.7/site-packages/SQLAlchemy-0.8.2-py2.7-macosx-10.8-x86_64.egg/sqlalchemy/engine/__init__.py", line 332, in create_engine
    return strategy.create(*args, **kwargs)
  File "/Users/marshall/.virtualenvs/billy/lib/python2.7/site-packages/SQLAlchemy-0.8.2-py2.7-macosx-10.8-x86_64.egg/sqlalchemy/engine/strategies.py", line 64, in create
    dbapi = dialect_cls.dbapi(**dbapi_args)
  File "/Users/marshall/.virtualenvs/billy/lib/python2.7/site-packages/SQLAlchemy-0.8.2-py2.7-macosx-10.8-x86_64.egg/sqlalchemy/dialects/sqlite/pysqlite.py", line 295, in dbapi
    raise e
ImportError: No module named pysqlite2

Running pip install pysqlite fixes the issue but I'm not sure if the dependency is incorrect or if it's missing.

Import billy project module in either absolute or relative manner

It is better to import project modules in a certain package. For example, code like this

from models.base import Base, RelativeDelta
from models.groups import Group
from utils.generic import uuid_factory

Should rewrite in

from billy.models.base import Base, RelativeDelta
from billy.models.groups import Group
from billy.utils.generic import uuid_factory

style. Otherwise, you cannot understand which one is from your own project, which are from other third-party packages. Also, it will be error prone in certain situation. If it is a relative import, for example

+ billy 
    + models
        - module_a.py
        - module_b.py
    - module_c.py

In module_a.py, you can import module_b.py and module_c.py like this

from . import module_b
from .. import module_c

But you should notice that, when you use a relative manner, the module should be imported in a relative manner as well to import correctly. You cannot execute

python module_a.py

and expect it works. It would work when it is

python -m billy.models.module_a

It is executed (or imported) in a relative manner, then it can find parent module then the relative ones.

So, in most cases, absolute import style is recommended.

Figure out a way to make Balanced works with Billy

Original posted here:
https://github.com/PoundPay/balanced/issues/300

As the design of Balanced API doesn't allow us to charge bank account cross marketplaces, explained in following diagram

billy_balance_02

Therefore, we will need a marketplace dedicated for invoicing, and have all marketplace owner customer and their funding instruments to be cloned to that marketplace like this.

billy_balance_03

The approach we will use is to emit events about adding funding instruments (and all necessary operations), then let the syncer subscribes to these events, and duplicate these records into our marketplace for invoicing.

Fix misleading external_id parameter for creating a customer

As the naming external_id implies, sounds it should be an ID, so user may misunderstand it, they may think it should be a GUID like CUXXXXXXX... from balanced service. However, it actually accepts only a complete URI in /v1/customers/CUXXXXX format. In that way, user may waste their time in trying it with invalid customer external id.

I am thinking renaming the external_id to external_uri, it would be more clear that it is an URI rather than an ID. Also, I think maybe we can call Balanced API before creating a customer record in Billy to make sure the given value is valid. By make failure happens as earlier as possible, users don't have to wait for a period to see what's wrong there from transactions error message.

`vagrant up` not running successfully for me on OSX

I get the following output:

| => vagrant up
Failed to load the "vagrant-butcher" plugin. View logs for more details.

Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'precise64'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- /vagrant
[default] -- /tmp/vagrant-chef-1/chef-solo-1/cookbooks
[default] Running provisioner: shell...
[default] Running: inline script
stdin: is not a tty
Successfully installed mixlib-cli-1.3.0
Successfully installed net-ssh-2.7.0
Successfully installed chef-11.6.0
3 gems installed
[default] Running provisioner: chef_solo...
Generating chef JSON and uploading...
Running chef-solo...
stdin: is not a tty
[2013-10-08T15:54:37+00:00] INFO: Forking chef instance to converge...
[2013-10-08T15:54:37+00:00] INFO: *** Chef 11.6.0 ***
[2013-10-08T15:54:37+00:00] INFO: Setting the run_list to ["recipe[billy]"] from JSON
[2013-10-08T15:54:37+00:00] INFO: Run List is [recipe[billy]]
[2013-10-08T15:54:37+00:00] INFO: Run List expands to [billy]
[2013-10-08T15:54:37+00:00] INFO: Starting Chef Run for precise64
[2013-10-08T15:54:37+00:00] INFO: Running start handlers
[2013-10-08T15:54:37+00:00] INFO: Start handlers complete.
[2013-10-08T15:54:38+00:00] INFO: ohai plugins will be at: /etc/chef/ohai_plugins
[2013-10-08T15:54:38+00:00] INFO: remote_directory[/etc/chef/ohai_plugins] created directory /etc/chef/ohai_plugins
[2013-10-08T15:54:38+00:00] INFO: remote_directory[/etc/chef/ohai_plugins] mode changed to 755
[2013-10-08T15:54:38+00:00] INFO: cookbook_file[/etc/chef/ohai_plugins/README] created file /etc/chef/ohai_plugins/README
[2013-10-08T15:54:38+00:00] INFO: cookbook_file[/etc/chef/ohai_plugins/README] updated file contents /etc/chef/ohai_plugins/README
[2013-10-08T15:54:38+00:00] INFO: cookbook_file[/etc/chef/ohai_plugins/README] mode changed to 644
[2013-10-08T15:54:38+00:00] INFO: ohai[custom_plugins] reloaded
[2013-10-08T15:54:43+00:00] INFO: execute[apt-get-update-build-essentials] ran successfully
[2013-10-08T15:55:05+00:00] WARN: Cloning resource attributes for service[nginx] from prior resource (CHEF-3694)
[2013-10-08T15:55:05+00:00] WARN: Current  service[nginx]: /tmp/vagrant-chef-1/chef-solo-1/cookbooks/nginx/recipes/source.rb:114:in `from_file'
[2013-10-08T15:55:05+00:00] WARN: Cloning resource attributes for execute[apt-get update] from prior resource (CHEF-3694)
[2013-10-08T15:55:05+00:00] WARN: Previous execute[apt-get update]: /tmp/vagrant-chef-1/chef-solo-1/cookbooks/apt/recipes/default.rb:29:in `from_file'
[2013-10-08T15:55:05+00:00] WARN: Current  execute[apt-get update]: /tmp/vagrant-chef-1/chef-solo-1/cookbooks/postgresql/recipes/ruby.rb:27:in `from_file'
[2013-10-08T15:55:09+00:00] INFO: execute[apt-get update] ran successfully
[2013-10-08T15:55:34+00:00] INFO: execute[apt-get-update] ran successfully
[2013-10-08T15:55:36+00:00] INFO: package[update-notifier-common] sending run action to execute[apt-get-update] (immediate)
[2013-10-08T15:55:41+00:00] INFO: execute[apt-get-update] ran successfully
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local] created directory /var/cache/local
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local] owner changed to 0
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local] group changed to 0
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local] mode changed to 755
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local/preseeding] created directory /var/cache/local/preseeding
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local/preseeding] owner changed to 0
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local/preseeding] group changed to 0
[2013-10-08T15:55:41+00:00] INFO: directory[/var/cache/local/preseeding] mode changed to 755
[2013-10-08T15:56:01+00:00] INFO: remote_file[/var/chef/cache/ez_setup.py] created file /var/chef/cache/ez_setup.py
[2013-10-08T15:56:02+00:00] INFO: remote_file[/var/chef/cache/ez_setup.py] updated file contents /var/chef/cache/ez_setup.py
[2013-10-08T15:56:02+00:00] INFO: remote_file[/var/chef/cache/ez_setup.py] mode changed to 644
[2013-10-08T15:56:02+00:00] INFO: remote_file[/var/chef/cache/get-pip.py] created file /var/chef/cache/get-pip.py
[2013-10-08T15:56:03+00:00] INFO: remote_file[/var/chef/cache/get-pip.py] updated file contents /var/chef/cache/get-pip.py
[2013-10-08T15:56:03+00:00] INFO: remote_file[/var/chef/cache/get-pip.py] mode changed to 644
[2013-10-08T15:56:03+00:00] INFO: execute[install-setuptools] ran successfully
[2013-10-08T15:56:05+00:00] INFO: execute[install-pip] ran successfully
[2013-10-08T15:56:05+00:00] INFO: Installing python_pip[virtualenv] version latest
[2013-10-08T15:56:06+00:00] INFO: user[www-data] altered
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] created file /etc/chef/ohai_plugins/nginx.rb
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] updated file contents /etc/chef/ohai_plugins/nginx.rb
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: template[/etc/chef/ohai_plugins/nginx.rb] sending reload action to ohai[reload_nginx] (immediate)
[2013-10-08T15:56:07+00:00] INFO: ohai[reload_nginx] reloaded
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx] created directory /etc/nginx
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: directory[/var/log/nginx] created directory /var/log/nginx
[2013-10-08T15:56:07+00:00] INFO: directory[/var/log/nginx] owner changed to 33
[2013-10-08T15:56:07+00:00] INFO: directory[/var/log/nginx] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-available] created directory /etc/nginx/sites-available
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-available] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-available] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-available] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-enabled] created directory /etc/nginx/sites-enabled
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-enabled] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-enabled] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/sites-enabled] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/conf.d] created directory /etc/nginx/conf.d
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/conf.d] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/conf.d] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: directory[/etc/nginx/conf.d] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxensite] created file /usr/sbin/nxensite
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxensite] updated file contents /usr/sbin/nxensite
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxensite] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxensite] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxensite] mode changed to 755
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxdissite] created file /usr/sbin/nxdissite
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxdissite] updated file contents /usr/sbin/nxdissite
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxdissite] owner changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxdissite] group changed to 0
[2013-10-08T15:56:07+00:00] INFO: template[/usr/sbin/nxdissite] mode changed to 755
[2013-10-08T15:56:10+00:00] INFO: remote_file[http://nginx.org/download/nginx-1.2.9.tar.gz] created file /var/chef/cache/nginx-1.2.9.tar.gz
[2013-10-08T15:56:10+00:00] INFO: remote_file[http://nginx.org/download/nginx-1.2.9.tar.gz] updated file contents /var/chef/cache/nginx-1.2.9.tar.gz
[2013-10-08T15:56:10+00:00] INFO: template[nginx.conf] created file /etc/nginx/nginx.conf
[2013-10-08T15:56:10+00:00] INFO: template[nginx.conf] updated file contents /etc/nginx/nginx.conf
[2013-10-08T15:56:10+00:00] INFO: template[nginx.conf] owner changed to 0
[2013-10-08T15:56:10+00:00] INFO: template[nginx.conf] group changed to 0
[2013-10-08T15:56:10+00:00] INFO: template[nginx.conf] mode changed to 644
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] created file /etc/nginx/sites-available/default
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] updated file contents /etc/nginx/sites-available/default
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] owner changed to 0
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] group changed to 0
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] mode changed to 644
[2013-10-08T15:56:10+00:00] INFO: template[/etc/nginx/sites-available/default] not queuing delayed action reload on service[nginx] (delayed), as it's already been queued
[2013-10-08T15:56:11+00:00] INFO: execute[nxensite default] ran successfully
[2013-10-08T15:56:11+00:00] INFO: execute[nxensite default] not queuing delayed action reload on service[nginx] (delayed), as it's already been queued
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] created file /etc/nginx/mime.types
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] updated file contents /etc/nginx/mime.types
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] owner changed to 0
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] group changed to 0
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] mode changed to 644
[2013-10-08T15:56:11+00:00] INFO: cookbook_file[/etc/nginx/mime.types] not queuing delayed action reload on service[nginx] (delayed), as it's already been queued
[2013-10-08T15:56:34+00:00] INFO: bash[compile_nginx_source] ran successfully
[2013-10-08T15:56:34+00:00] WARN: Method 'template_location' of 'Chef::Provider::Template' is deprecated. It will be removed in Chef 12.
[2013-10-08T15:56:34+00:00] WARN: Please update your cookbooks accordingly. Accessed from:
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider/package.rb:207:in `preseed_resource'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider/package.rb:182:in `get_preseed_file'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider/package.rb:73:in `action_install'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider.rb:114:in `send'
[2013-10-08T15:56:34+00:00] WARN: Method 'template_finder' of 'Chef::Provider::Template' is deprecated. It will be removed in Chef 12.
[2013-10-08T15:56:34+00:00] WARN: Please update your cookbooks accordingly. Accessed from:
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/deprecation/provider/template.rb:42:in `template_location'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/deprecation/warnings.rb:30:in `template_location'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider/package.rb:207:in `preseed_resource'
[2013-10-08T15:56:34+00:00] WARN: /opt/vagrant_ruby/lib/ruby/gems/1.8/gems/chef-11.6.0/bin/../lib/chef/provider/package.rb:182:in `get_preseed_file'
[2013-10-08T15:56:34+00:00] INFO: cookbook_file[/var/chef/cache/preseed/runit/runit-2.1.1-6.2ubuntu2.seed] created file /var/chef/cache/preseed/runit/runit-2.1.1-6.2ubuntu2.seed
[2013-10-08T15:56:34+00:00] INFO: cookbook_file[/var/chef/cache/preseed/runit/runit-2.1.1-6.2ubuntu2.seed] updated file contents /var/chef/cache/preseed/runit/runit-2.1.1-6.2ubuntu2.seed
[2013-10-08T15:56:34+00:00] INFO: package[runit] pre-seeding package installation instructions
[2013-10-08T15:56:36+00:00] INFO: package[runit] sending nothing action to execute[start-runsvdir] (immediate)
[2013-10-08T15:56:36+00:00] INFO: package[runit] sending nothing action to execute[runit-hup-init] (immediate)
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx] created directory /etc/sv/nginx
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx] mode changed to 755
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/run] created file /etc/sv/nginx/run
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/run] updated file contents /etc/sv/nginx/run
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/run] mode changed to 755
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx/log] created directory /etc/sv/nginx/log
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx/log] mode changed to 755
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx/log/main] created directory /etc/sv/nginx/log/main
[2013-10-08T15:56:36+00:00] INFO: directory[/etc/sv/nginx/log/main] mode changed to 755
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/run] created file /etc/sv/nginx/log/run
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/run] updated file contents /etc/sv/nginx/log/run
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/run] mode changed to 755
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/config] created file /etc/sv/nginx/log/config
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/config] updated file contents /etc/sv/nginx/log/config
[2013-10-08T15:56:36+00:00] INFO: template[/etc/sv/nginx/log/config] mode changed to 644
[2013-10-08T15:56:36+00:00] INFO: link[/etc/init.d/nginx] created
[2013-10-08T15:56:36+00:00] INFO: runit_service[nginx] configured
[2013-10-08T15:56:36+00:00] INFO: link[/etc/service/nginx] created
[2013-10-08T15:56:41+00:00] INFO: runit_service[nginx] enabled
[2013-10-08T15:56:42+00:00] INFO: directory[/etc/postgresql/9.1/main] created directory /etc/postgresql/9.1/main
[2013-10-08T15:56:42+00:00] INFO: directory[/etc/postgresql/9.1/main] mode changed to 777
[2013-10-08T15:56:42+00:00] INFO: directory[/var/log/postgresql] created directory /var/log/postgresql
[2013-10-08T15:56:42+00:00] INFO: directory[/var/log/postgresql] mode changed to 777

================================================================================
Error executing action `create` on resource 'template[/etc/postgresql/9.1/main/postgresql.conf]'
================================================================================


Chef::Exceptions::UserIDNotFound
--------------------------------
cannot determine user id for 'postgres', does the user exist on this system?


Resource Declaration:
---------------------
# In /tmp/vagrant-chef-1/chef-solo-1/cookbooks/postgresql/recipes/server.rb

 66: template "#{node['postgresql']['dir']}/postgresql.conf" do
 67:   source "postgresql.conf.erb"
 68:   owner "postgres"
 69:   group "postgres"
 70:   mode 0600
 71:   notifies :restart, 'service[postgresql]', :immediately
 72: end
 73: 



Compiled Resource:
------------------
# Declared in /tmp/vagrant-chef-1/chef-solo-1/cookbooks/postgresql/recipes/server.rb:66:in `from_file'

template("/etc/postgresql/9.1/main/postgresql.conf") do
  owner "postgres"
  action "create"
  recipe_name "server"
  retry_delay 2
  cookbook_name :postgresql
  backup 5
  path "/etc/postgresql/9.1/main/postgresql.conf"
  source "postgresql.conf.erb"
  mode 384
  retries 0
  provider Chef::Provider::Template
  group "postgres"
  atomic_update true
end



[2013-10-08T15:56:42+00:00] INFO: Running queued delayed notifications before re-raising exception
[2013-10-08T15:56:42+00:00] INFO: template[nginx.conf] sending reload action to service[nginx] (delayed)
[2013-10-08T15:56:42+00:00] INFO: service[nginx] reloaded
[2013-10-08T15:56:42+00:00] INFO: bash[compile_nginx_source] sending restart action to service[nginx] (delayed)
[2013-10-08T15:56:44+00:00] INFO: service[nginx] restarted
[2013-10-08T15:56:44+00:00] ERROR: Running exception handlers
[2013-10-08T15:56:44+00:00] ERROR: Exception handlers complete
[2013-10-08T15:56:44+00:00] FATAL: Stacktrace dumped to /var/chef/cache/chef-stacktrace.out
[2013-10-08T15:56:44+00:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)
Chef never successfully completed! Any errors should be visible in the
output above. Please fix your recipes so that they properly complete.
________________________________________________________________________________
| ~/code/balanced/billy @ mjallday-2 (master) 
| => 

I started with a clean slate by running vagrant destroy && vagrant up

Define invoicing usage scenario

With some inputs from a customer and the scenario of how invoice is processed in balanced, I have a better understanding of what invoicing should be. For now, I am staring to describe usage scenarios here, improve the design gradually, and implement it when it looks good.

Some wanted features here:

  • Emailing customer when a invoice is generated
  • Generating invoices based on usage

Unlike what the most obvious usage scenario we mentioned in the previous development cycle, common hosting service providers can use billy to charge or payout a fixed amount to specific customers. However, not all of hosting service providers, or cloud service providers are charging customers in a fixed rate. Such as Amazon Web Service, the price is basically determined by the usage. In this case, we want our customer to be able to charge customer based on metered usage. Another good example is Balanced itself, customer are charged based on transaction count. This is great, we can eat our own dog food at very first.

As we need to grab usage data from the user side, I think there are two obvious ways to do

  • Pull from user server via HTTP periodically
  • Push by user to billy

Still thinking pros and cons of these two approaches, however, maybe we can implement them all. But anyway, the data should contain

  • Amount to charge
  • Customers to charge
  • Email addresses to notify (optional)
  • Title (optional) (to be displayed in email)
  • Items (optional) (to be displayed in email)

I envision the data format of a invoice may look like this

amount: 100
customer: customer_guid
title: Foobar Super Cloud Service October Invoice
items:
    - name: Bandwidth usage
      count: 10
      unit: TB 
      amount: 20
    - name: Instance usage
      count: 200
      unit: hours
      amount: 80
notify_email:
    - [email protected]
    - [email protected]

On receiving these data from end of user, billy then generate corresponding invoice, send email to receivers and charge customers if it is necessary.

TODO:

  • design API calls
  • ERD diagram

Can frequency have an "frequency length" ?

"Frequency length" probably isn't the best term to use, but we sell our subscriptions in the following intervals:

  • 1 month
  • 2 months
  • 3 months
  • 4 months
  • 6 months
  • 12 months / 1 year
  • 24 months / 2 years
  • 36 months / 3 years

Maybe add another optional property to Frequency(object)?

Write a tutorial

I just found this sweet recurring billing software called Billy. It looks totally awesome but I don't know how to use it. It sure would be cool if there was a tutorial that showed me how :)

Setup beta environment

@mahmoudimus @mjallday @msherry

As we know there are customers waiting for billy beta environment. I think we should setup one as soon as possible. Almost everything is ready to go.

We have a Chef repo for deploying it

https://github.com/victorlin/billy-chef

It is already running on my own EC2 instance mentioned at #44, but I don't think it is a good idea to run Balanced service on my own instance. I think we are using EC2 for deployment aren't we? If we are, we have two options

1. I deploy it by my-self

I think I can do the deployment and maintenance by myself, you can setup a account via AWS Identity and Access Management with minimum permission to run an EC2 instance, and rest of it is my DIY time.

2. Deploy by others

I am not sure how deployment is done usually, maybe someone can deploy it for us.

I am all okay for these two options. See what youguys think.

Make soft description can be changed by user

As I see soft description for transaction is pretty important for reasons, and Billy currently doesn't allow user to set a soft description for transactions issued either by invoice or recurring payment, I think this is a must to have feature. Will add it after invoicing feature is finished.

Automatic Subscriptions

(migrated from balanced/balanced-api#183)

Program API interface to show usage:

buyer = balanced.Buyer.new( <account details> )

subscription = balanced.Subscription.get( <subscription id/name> )

subscription.enroll( buyer )

For reasoning. As a Balanced user I should not have to perform manual subscription handling, unless I need that control. Balanced should handle subscription creation, pricing, subscription interval, and apply filters to the subscription to effect payments, such as coupons.

I currently handle the subscription process, but have noticed that other services offer the above through their API thus removing the work further from me and allowing me to focus on my application instead of intricate details that ultimately I should not have to worry about.

How to handle 'months' in recurring billing

Currently months are handled using dateutil's relativedelta. A sample output:

day_start = datetime(year=2012,month=1, day=29)
for each in range(20):
... day_start += relativedelta(months=1)
... print day_start
...
2012-02-29 00:00:00
2012-03-29 00:00:00
2012-04-29 00:00:00
2012-05-29 00:00:00
2012-06-29 00:00:00
2012-07-29 00:00:00
2012-08-29 00:00:00
2012-09-29 00:00:00
2012-10-29 00:00:00
2012-11-29 00:00:00
2012-12-29 00:00:00
2013-01-29 00:00:00
2013-02-28 00:00:00
2013-03-28 00:00:00
2013-04-28 00:00:00
2013-05-28 00:00:00
2013-06-28 00:00:00
2013-07-28 00:00:00
2013-08-28 00:00:00
2013-09-28 00:00:00

How good is this 'monthly' strategy for a recurring billing system? Someone pointed out this http://bit.ly/15gLHsZ as an alternative strategy. I think this way makes more sense because you stay within the scope of the current month and it automatically adjusts for leapyears, shorter months, etc.

Write an easy-to-use Python API client

Although billy has a RESTful API, it is still better to have a easy-to-use Python API client library that the usage might like what I mentioned in #25.

However, this is not a priority task as the API may not be stable for a period. Also, we should take care of naming problem as billy is already used by the server project. Maybe we can use billy-client for Python project name (in PyPi and github repo). And for Python package name (the_name/init.py), we can use billy_client, or we can use a Python namespace package ( http://www.python.org/dev/peps/pep-0382/ ), make it under billy.client? Well, not priority, think about it later.

Feature: Refill Billing

Scenario:
-Customer account balance automatically add $20 everytime the balance reaches $5
-Predefined microcharges reduce balance e.g. $0.01 per SMS reduce balance

Good billing/payment strategy for low cost products. Works well with creditline billing (see other feature)

Decide the API style

The current REST API design is pretty much like what I mentioned in #33 (comment) . I try to make it looks like Balanced API, however, there are something different from details to details.

The Balanced API uses URI as the ID for passing around, I don't know the design rationale here (about version distinguishing?). Maybe we can adjust it to do the same way.

Also, for Balanced API, some relative record will be returned when retrieving one record. For example, you get a Debit, there will be customer data or something like that in the response json body. I think the rationale here is for efficiency? (save some extra requests?). Anyway, I can also make the same to billy API, just need some rules of thumb to decide which relative records to include, and how deep it should be.

Float number rounding up policy?

As we are processing money, I think maybe we should be careful with float numbers rounding up issue. Currently, I use

Numeric(10, 2)

for all money fields (also for discount field). I am not sure are two digits float number good enough. Also, we have discount for subscriptions, and we have prorated_refund for canceling a subscription. In this two cases, money amount could be rated. It could be

amount = original_amount * discount * prorated

After all, I have no money processing experience. I have no idea how to process them. Is there anything I should notice? What do youguys think?

Create Vagrant environment and Chef code for integration testing and deployment

For now we have unit tests and functional tests, but we don't have easy-to-setup integration testing environment yet. To make it as easy as possible to run integration tests and deploy, we should write a Vagrant environment with Chef code for it. Then we can run it easily like

git clone https://github.com/balanced/billy.git
cd billy
vagrant up

As I don't think it is a good idea to include Chef code directly in this project, I think we can use a .gitmodule file to include chef code from another repo. The .gitmodule might look like this.

[submodule "chef"]
    path = chef
    url = git://github.com/balanced/billy-chef

What is the preferred Linux distribution youguys are using? Ubuntu 12.04.3 LTS (Precise Pangolin)?

Dogfooding

Once invoicing is implemented the best way to ensure that this code works as required will be to get Balanced to use it for production invoicing of marketplace fees.

A 3-step approach would be best

  1. Create invoices via Billy alongside Balanced invoices and compare the results
  2. Reconcile Billy invoices alongside Balanced invoices and compare the results
  3. Submit invoices via Billy instead of via Balanced (the end!)

We have an internal discussion at Balanced on how to implement step 1.

It's unclear how Billy will handle invoice adjustments right now but once that is understood we can begin generate the invoices in Billy.

Keep coding style in PEP8

Maybe we should keep the coding style more closer to PEP8. It doesn't have to be 100% PEP8 style, as some of these rules are not required in certain situations (we can ignore that in flake8 configuration), for example, the E601, line too long rule, when we can always view and edit code in a big screen, this might not be too important.

However, the current PEP8 compliance situation is horrible. This would certain reduce readability to the code. Please read PEP8 article:

http://www.python.org/dev/peps/pep-0008/

And run flake8 ( https://pypi.python.org/pypi/flake8 ) with tests like this

flake8 billy

If you are using SublimeText, you can install SublimeLinter plugin

https://github.com/SublimeLinter/SublimeLinter

It can tell you which lines have coding style issue, which kind of issue it is

linter

Current flake8 output:

billy\manage.py:5:1: F403 'from billy.models import *' used; unable to detect undefined names
billy\api\__init__.py:16:80: E501 line too long (83 > 79 characters)
billy\api\__init__.py:46:80: E501 line too long (89 > 79 characters)
billy\api\__init__.py:55:80: E501 line too long (98 > 79 characters)
billy\api\spec.py:8:1: F403 'from resources import *' used; unable to detect undefined names
billy\api\spec.py:60:24: E231 missing whitespace after ':'
billy\api\resources\__init__.py:2:1: F401 'Base' imported but unused
billy\api\resources\__init__.py:5:1: F401 'Home' imported but unused
billy\api\resources\__init__.py:8:1: F401 'GroupController' imported but unused
billy\api\resources\__init__.py:9:1: F401 'CustomerController' imported but unused
billy\api\resources\__init__.py:9:1: F401 'CustomerCreateForm' imported but unused
billy\api\resources\__init__.py:9:1: F401 'CustomerIndexController' imported but unused
billy\api\resources\__init__.py:9:1: F401 'CustomerUpdateForm' imported but unused
billy\api\resources\__init__.py:9:1: F401 'customer_view' imported but unused
billy\api\resources\__init__.py:10:37: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:11:37: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:12:1: F401 'CouponController' imported but unused
billy\api\resources\__init__.py:12:1: F401 'CouponCreateForm' imported but unused
billy\api\resources\__init__.py:12:1: F401 'CouponIndexController' imported but unused
billy\api\resources\__init__.py:12:1: F401 'CouponUpdateForm' imported but unused
billy\api\resources\__init__.py:12:1: F401 'coupon_view' imported but unused
billy\api\resources\__init__.py:12:80: E501 line too long (80 > 79 characters)
billy\api\resources\__init__.py:13:35: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:14:37: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:15:1: F401 'PlanController' imported but unused
billy\api\resources\__init__.py:15:1: F401 'PlanCreateForm' imported but unused
billy\api\resources\__init__.py:15:1: F401 'PlanIndexController' imported but unused
billy\api\resources\__init__.py:15:1: F401 'PlanUpdateForm' imported but unused
billy\api\resources\__init__.py:15:1: F401 'plan_view' imported but unused
billy\api\resources\__init__.py:15:80: E501 line too long (117 > 79 characters)
billy\api\resources\__init__.py:16:1: F401 'PayoutController' imported but unused
billy\api\resources\__init__.py:16:1: F401 'PayoutCreateForm' imported but unused
billy\api\resources\__init__.py:16:1: F401 'PayoutIndexController' imported but unused
billy\api\resources\__init__.py:16:1: F401 'PayoutUpdateForm' imported but unused
billy\api\resources\__init__.py:16:1: F401 'payout_view' imported but unused
billy\api\resources\__init__.py:16:80: E501 line too long (80 > 79 characters)
billy\api\resources\__init__.py:17:35: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:17:80: E501 line too long (82 > 79 characters)
billy\api\resources\__init__.py:18:1: F401 'PlanSubController' imported but unused
billy\api\resources\__init__.py:18:1: F401 'PlanSubCreateForm' imported but unused
billy\api\resources\__init__.py:18:1: F401 'PlanSubDeleteForm' imported but unused
billy\api\resources\__init__.py:18:1: F401 'PlanSubIndexController' imported but unused
billy\api\resources\__init__.py:18:1: F401 'plan_sub_view' imported but unused
billy\api\resources\__init__.py:19:46: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:19:80: E501 line too long (116 > 79 characters)
billy\api\resources\__init__.py:20:1: F401 'PayoutSubController' imported but unused
billy\api\resources\__init__.py:20:1: F401 'PayoutSubCreateForm' imported but unused
billy\api\resources\__init__.py:20:1: F401 'PayoutSubDeleteForm' imported but unused
billy\api\resources\__init__.py:20:1: F401 'PayoutSubIndexController' imported but unused
billy\api\resources\__init__.py:20:1: F401 'payout_sub_view' imported but unused
billy\api\resources\__init__.py:21:48: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:22:48: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:22:80: E501 line too long (105 > 79 characters)
billy\api\resources\__init__.py:23:1: F401 'PlanInvController' imported but unused
billy\api\resources\__init__.py:23:1: F401 'PlanInvIndexController' imported but unused
billy\api\resources\__init__.py:23:1: F401 'plan_inv_view' imported but unused
billy\api\resources\__init__.py:24:41: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:25:1: F401 'PayoutInvController' imported but unused
billy\api\resources\__init__.py:25:1: F401 'PayoutInvIndexController' imported but unused
billy\api\resources\__init__.py:25:1: F401 'payout_inv_view' imported but unused
billy\api\resources\__init__.py:26:43: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:27:43: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:28:1: F401 'PlanTransController' imported but unused
billy\api\resources\__init__.py:28:1: F401 'PlanTransIndexController' imported but unused
billy\api\resources\__init__.py:28:1: F401 'plan_trans_view' imported but unused
billy\api\resources\__init__.py:29:45: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:30:45: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:31:1: F401 'PayoutTransController' imported but unused
billy\api\resources\__init__.py:31:1: F401 'PayoutTransIndexController' imported but unused
billy\api\resources\__init__.py:31:1: F401 'payout_trans_view' imported but unused
billy\api\resources\__init__.py:32:47: E128 continuation line under-indented for visual indent
billy\api\resources\__init__.py:33:47: E128 continuation line under-indented for visual indent
billy\api\resources\base\__init__.py:48:1: F821 undefined name 'unpack'
billy\api\resources\coupon\form.py:3:1: F403 'from sqlalchemy.exc import *' used; unable to detect undefined names
billy\api\resources\coupon\form.py:30:5: E303 too many blank lines (2)
billy\api\resources\customer\form.py:3:1: F403 'from sqlalchemy.exc import *' used; unable to detect undefined names
billy\api\resources\group\__init__.py:56:5: E303 too many blank lines (2)
billy\api\resources\group\__init__.py:64:1: W391 blank line at end of file
billy\api\resources\payout\form.py:3:1: F403 'from sqlalchemy.exc import *' used; unable to detect undefined names
billy\api\resources\payout\form.py:13:41: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:29:5: E303 too many blank lines (2)
billy\api\resources\payout\form.py:36:34: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:37:34: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:38:34: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:39:34: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:40:34: E128 continuation line under-indented for visual indent
billy\api\resources\payout\form.py:41:34: E124 closing bracket does not match visual indentation
billy\api\resources\payout_invoice\__init__.py:8:80: E501 line too long (81 > 79 characters)
billy\api\resources\payout_invoice\__init__.py:23:80: E501 line too long (84 > 79 characters)
billy\api\resources\payout_subscription\form.py:3:1: F403 'from sqlalchemy.orm.exc import *' used; unable to detect undefined names
billy\api\resources\payout_subscription\form.py:15:41: E128 continuation line under-indented for visual indent
billy\api\resources\payout_subscription\form.py:41:41: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:3:1: F403 'from sqlalchemy.exc import *' used; unable to detect undefined names
billy\api\resources\plan\form.py:13:37: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:43:32: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:44:32: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:45:32: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:46:32: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:47:32: E128 continuation line under-indented for visual indent
billy\api\resources\plan\form.py:48:32: E124 closing bracket does not match visual indentation
billy\api\resources\plan_invoice\__init__.py:8:80: E501 line too long (81 > 79 characters)
billy\api\resources\plan_invoice\__init__.py:23:80: E501 line too long (84 > 79 characters)
billy\api\resources\plan_subscription\form.py:3:1: F403 'from sqlalchemy.orm.exc import *' used; unable to detect undefined names
billy\api\resources\plan_subscription\form.py:15:37: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:32:47: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:33:47: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:33:80: E501 line too long (98 > 79 characters)
billy\api\resources\plan_subscription\form.py:34:47: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:34:80: E501 line too long (87 > 79 characters)
billy\api\resources\plan_subscription\form.py:43:37: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:56:49: E128 continuation line under-indented for visual indent
billy\api\resources\plan_subscription\form.py:56:80: E501 line too long (113 > 79 characters)
billy\models\__init__.py:4:1: F401 'ProcessorType' imported but unused
billy\models\__init__.py:5:1: F401 'Base' imported but unused
billy\models\__init__.py:7:1: F401 'ChargeSubscription' imported but unused
billy\models\__init__.py:8:1: F401 'PayoutSubscription' imported but unused
billy\models\__init__.py:9:1: F401 'ChargePlanInvoice' imported but unused
billy\models\__init__.py:10:1: F401 'PayoutPlanInvoice' imported but unused
billy\models\__init__.py:11:1: F401 'ChargeTransaction' imported but unused
billy\models\__init__.py:11:1: F401 'ChargeTransactionStatus' imported but unused
billy\models\__init__.py:12:1: F401 'PayoutTransaction' imported but unused
billy\models\__init__.py:12:1: F401 'PayoutTransactionStatus' imported but unused
billy\models\__init__.py:13:1: F401 'PayoutPlan' imported but unused
billy\models\__init__.py:14:1: F401 'ChargePlan' imported but unused
billy\models\__init__.py:15:1: F401 'Customer' imported but unused
billy\models\__init__.py:16:1: F401 'Coupon' imported but unused
billy\models\__init__.py:17:1: F401 'Company' imported but unused
billy\models\base.py:6:1: F401 'event' imported but unused
billy\models\base.py:25:80: E501 line too long (82 > 79 characters)
billy\models\company.py:3:1: F401 'Enum' imported but unused
billy\models\company.py:3:1: F401 'ForeignKey' imported but unused
billy\models\company.py:4:1: F401 'backref' imported but unused
billy\models\company.py:6:80: E501 line too long (86 > 79 characters)
billy\models\company.py:45:5: E303 too many blank lines (4)
billy\models\company.py:105:15: E225 missing whitespace around operator
billy\models\company.py:119:5: E303 too many blank lines (2)
billy\models\company.py:152:80: E501 line too long (83 > 79 characters)
billy\models\coupons.py:4:1: F401 'Boolean' imported but unused
billy\models\coupons.py:17:80: E501 line too long (80 > 79 characters)
billy\models\coupons.py:75:5: E303 too many blank lines (2)
billy\models\coupons.py:79:80: E501 line too long (80 > 79 characters)
billy\models\coupons.py:91:5: E303 too many blank lines (2)
billy\models\customers.py:4:1: F401 'Integer' imported but unused
billy\models\customers.py:17:80: E501 line too long (80 > 79 characters)
billy\models\customers.py:24:40: E128 continuation line under-indented for visual indent
billy\models\customers.py:46:5: E303 too many blank lines (2)
billy\models\customers.py:50:44: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\customers.py:53:5: E303 too many blank lines (2)
billy\models\customers.py:57:42: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\customers.py:60:1: W391 blank line at end of file
billy\models\charge\invoice.py:76:45: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\charge\invoice.py:90:35: E127 continuation line over-indented for visual indent
billy\models\charge\invoice.py:96:80: E501 line too long (83 > 79 characters)
billy\models\charge\invoice.py:137:5: E303 too many blank lines (2)
billy\models\charge\plan.py:19:80: E501 line too long (80 > 79 characters)
billy\models\charge\plan.py:34:5: E124 closing bracket does not match visual indentation
billy\models\charge\subscription.py:19:80: E501 line too long (80 > 79 characters)
billy\models\charge\subscription.py:35:45: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\charge\subscription.py:40:5: E303 too many blank lines (2)
billy\models\charge\subscription.py:84:5: E303 too many blank lines (2)
billy\models\charge\subscription.py:104:5: E303 too many blank lines (2)
billy\models\charge\subscription.py:115:13: E122 continuation line missing indentation or outdented
billy\models\charge\subscription.py:115:34: E711 comparison to None should be 'if cond is None:'
billy\models\charge\transaction.py:4:1: F401 'relationship' imported but unused
billy\models\charge\transaction.py:11:26: E128 continuation line under-indented for visual indent
billy\models\charge\transaction.py:35:80: E501 line too long (84 > 79 characters)
billy\models\charge\transaction.py:45:27: W292 no newline at end of file
billy\models\payout\invoice.py:34:5: E124 closing bracket does not match visual indentation
billy\models\payout\invoice.py:54:63: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\payout\invoice.py:75:32: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\payout\invoice.py:81:5: E303 too many blank lines (2)
billy\models\payout\invoice.py:85:57: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
billy\models\payout\invoice.py:118:1: W391 blank line at end of file
billy\models\payout\plan.py:18:80: E501 line too long (80 > 79 characters)
billy\models\payout\plan.py:23:36: E124 closing bracket does not match visual indentation
billy\models\payout\plan.py:32:5: E124 closing bracket does not match visual indentation
billy\models\payout\plan.py:52:28: W292 no newline at end of file
billy\models\payout\subscription.py:3:1: F401 'DateTime' imported but unused
billy\models\payout\subscription.py:24:42: E712 comparison to True should be 'if cond is True:' or 'if cond:'
billy\models\payout\subscription.py:47:45: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
billy\models\payout\transaction.py:10:26: E128 continuation line under-indented for visual indent
billy\models\payout\transaction.py:28:5: E303 too many blank lines (2)
billy\models\payout\transaction.py:36:80: E501 line too long (82 > 79 characters)
billy\models\payout\transaction.py:46:27: W292 no newline at end of file
billy\models\processor\balanced.py:14:80: E501 line too long (82 > 79 characters)
billy\models\processor\dummy.py:14:80: E501 line too long (82 > 79 characters)
billy\settings\__init__.py:8:1: F403 'from all import *' used; unable to detect undefined names
billy\settings\__init__.py:10:1: F403 'from debug import *' used; unable to detect undefined names
billy\settings\__init__.py:12:1: F403 'from prod import *' used; unable to detect undefined names
billy\tests\__init__.py:18:80: E501 line too long (85 > 79 characters)
billy\tests\fixtures\__init__.py:3:1: F401 'sample_company' imported but unused
billy\tests\fixtures\__init__.py:4:1: F401 'sample_coupon' imported but unused
billy\tests\fixtures\__init__.py:5:1: F401 'sample_customer' imported but unused
billy\tests\fixtures\__init__.py:6:1: F401 'sample_payout' imported but unused
billy\tests\fixtures\__init__.py:7:1: F401 'sample_plan' imported but unused
billy\tests\fixtures\__init__.py:8:1: W391 blank line at end of file
billy\tests\fixtures\company.py:14:6: W292 no newline at end of file
billy\tests\fixtures\coupon.py:19:6: W292 no newline at end of file
billy\tests\test_api\__init__.py:17:1: E302 expected 2 blank lines, found 1
billy\tests\test_api\__init__.py:63:1: F821 undefined name 'TEST_API_KEYS'
billy\tests\test_api\test_coupon.py:4:5: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:6:80: E501 line too long (88 > 79 characters)
billy\tests\test_api\test_coupon.py:19:80: E501 line too long (83 > 79 characters)
billy\tests\test_api\test_coupon.py:31:5: E303 too many blank lines (2)
billy\tests\test_api\test_coupon.py:79:5: E303 too many blank lines (2)
billy\tests\test_api\test_coupon.py:109:26: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:113:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_coupon.py:114:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:115:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:119:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_coupon.py:120:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:137:9: E303 too many blank lines (2)
billy\tests\test_api\test_coupon.py:139:26: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:142:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_coupon.py:143:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:144:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_coupon.py:145:63: W292 no newline at end of file
billy\tests\test_api\test_customer.py:4:5: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:6:80: E501 line too long (88 > 79 characters)
billy\tests\test_api\test_customer.py:7:29: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:19:80: E501 line too long (83 > 79 characters)
billy\tests\test_api\test_customer.py:31:5: E303 too many blank lines (2)
billy\tests\test_api\test_customer.py:79:5: E303 too many blank lines (2)
billy\tests\test_api\test_customer.py:109:26: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:113:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_customer.py:114:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:115:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:119:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_customer.py:120:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:137:9: E303 too many blank lines (2)
billy\tests\test_api\test_customer.py:139:26: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:142:80: E501 line too long (80 > 79 characters)
billy\tests\test_api\test_customer.py:143:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:144:32: E128 continuation line under-indented for visual indent
billy\tests\test_api\test_customer.py:145:63: W292 no newline at end of file
billy\tests\test_models\test_charge_invoice.py:21:80: E501 line too long (82 > 79 characters)
billy\tests\test_models\test_charge_invoice.py:27:5: E303 too many blank lines (2)
billy\tests\test_models\test_charge_invoice.py:51:80: E501 line too long (80 > 79 characters)
billy\tests\test_models\test_charge_invoice.py:65:1: F841 local variable 'all_due_new' is assigned to but never used
billy\tests\test_models\test_charge_invoice.py:74:80: E501 line too long (91 > 79 characters)
billy\tests\test_models\test_charge_invoice.py:75:9: E303 too many blank lines (3)
billy\tests\test_models\test_charge_invoice.py:80:80: E501 line too long (81 > 79 characters)
billy\tests\test_models\test_charge_invoice.py:98:1: W391 blank line at end of file
billy\tests\test_models\test_charge_plan.py:20:34: E261 at least two spaces before inline comment
billy\tests\test_models\test_charge_plan.py:21:35: E261 at least two spaces before inline comment
billy\tests\test_models\test_charge_plan.py:22:30: E261 at least two spaces before inline comment
billy\tests\test_models\test_charge_plan.py:23:43: E261 at least two spaces before inline comment
billy\tests\test_models\test_charge_plan.py:24:42: E261 at least two spaces before inline comment
billy\tests\test_models\test_charge_plan.py:36:1: F841 local variable 'sub' is assigned to but never used
billy\tests\test_models\test_charge_plan.py:47:1: F841 local variable 'sub2' is assigned to but never used
billy\tests\test_models\test_charge_transaction.py:37:79: W292 no newline at end of file
billy\tests\test_models\test_company.py:2:1: F401 'datetime' imported but unused
billy\tests\test_models\test_company.py:14:5: E303 too many blank lines (2)
billy\tests\test_models\test_company.py:17:48: E261 at least two spaces before inline comment
billy\tests\test_models\test_company.py:19:26: E261 at least two spaces before inline comment
billy\tests\test_models\test_company.py:30:9: E303 too many blank lines (2)
billy\tests\test_models\test_company.py:39:9: E303 too many blank lines (2)
billy\tests\test_models\test_company.py:49:1: W391 blank line at end of file
billy\tests\test_models\test_coupon.py:20:5: E303 too many blank lines (2)
billy\tests\test_models\test_coupon.py:27:27: E261 at least two spaces before inline comment
billy\tests\test_models\test_coupon.py:42:9: E303 too many blank lines (3)
billy\tests\test_models\test_coupon.py:52:1: W391 blank line at end of file
billy\tests\test_models\test_interface.py:6:29: E128 continuation line under-indented for visual indent
billy\tests\test_models\test_interface.py:18:9: E303 too many blank lines (2)
billy\tests\test_models\test_interface.py:22:9: E303 too many blank lines (2)
billy\tests\test_models\test_interface.py:26:9: E303 too many blank lines (2)
billy\tests\test_models\test_interface.py:43:9: E303 too many blank lines (2)
billy\utils\__init__.py:1:1: F401 'Intervals' imported but unused
billy\utils\fields.py:21:80: E501 line too long (81 > 79 characters)
billy\utils\fields.py:27:1: E302 expected 2 blank lines, found 1
billy\utils\fields.py:49:1: E303 too many blank lines (3)
billy\utils\fields.py:95:80: E501 line too long (81 > 79 characters)
billy\utils\fields.py:126:1: E302 expected 2 blank lines, found 1
billy\utils\fields.py:143:80: E501 line too long (82 > 79 characters)
billy\utils\fields.py:212:80: E501 line too long (84 > 79 characters)
billy\utils\fields.py:243:1: E302 expected 2 blank lines, found 1
billy\utils\fields.py:252:80: E501 line too long (81 > 79 characters)
billy\utils\intervals.py:6:1: F401 'Field' imported but unused
billy\utils\intervals.py:6:1: F401 'TextField' imported but unused
billy\utils\intervals.py:15:80: E501 line too long (81 > 79 characters)
billy\utils\models.py:10:1: E302 expected 2 blank lines, found 1
billy\utils\models.py:21:1: E303 too many blank lines (3)
billy\utils\models.py:65:1: W391 blank line at end of file

Feature: Creditline billing

Similar to Refill billing but instead charges accumulate and clear after a certain limit.

Scenario:
-Give user a line of credit (e.g. $10)
-Charge microitems to balance
-Once balance hits line of credit a charge is made and the balance is cleared

Another good solution to microbilling.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.