/li>
  • 29 0
      product/admin.py
  • BIN
      product/admin.pyc
  • 77 0
      product/migrations/0001_initial.py
  • BIN
      product/migrations/0001_initial.pyc
  • 24 0
      product/migrations/0002_auto_20170619_1734.py
  • BIN
      product/migrations/0002_auto_20170619_1734.pyc
  • 0 0
      product/migrations/__init__.py
  • BIN
      product/migrations/__init__.pyc
  • 99 0
      product/models.py
  • BIN
      product/models.pyc
  • 4 0
      product/tests.py
  • 4 0
      product/views.py
  • 39 0
      requirements.txt
  • 0 0
      tamron/__init__.py
  • BIN
      tamron/__init__.pyc
  • 13 0
      tamron/basemodels.py
  • BIN
      tamron/basemodels.pyc
  • 16 0
      tamron/func_settings.py
  • BIN
      tamron/func_settings.pyc
  • 29 0
      tamron/local_settings.py
  • BIN
      tamron/local_settings.pyc
  • 254 0
      tamron/settings.py
  • BIN
      tamron/settings.pyc
  • 300 0
      tamron/static/tamron/js/jswe.js
  • 33 0
      tamron/urls.py
  • BIN
      tamron/urls.pyc
  • 2 0
      tamron/uwsgi.bak/shutdown.sh
  • 2 0
      tamron/uwsgi.bak/startup.sh
  • 27 0
      tamron/uwsgi.bak/tamron.ini
  • 35 0
      tamron/uwsgi.bak/tamron_nginx.conf
  • 15 0
      tamron/uwsgi.bak/uwsgi_params
  • 17 0
      tamron/wsgi.py
  • BIN
      tamron/wsgi.pyc
  • 0 0
      utils/__init__.py
  • BIN
      utils/__init__.pyc
  • 0 0
      utils/error/__init__.py
  • BIN
      utils/error/__init__.pyc
  • 62 0
      utils/error/errno_utils.py
  • BIN
      utils/error/errno_utils.pyc
  • 18 0
      utils/error/response_utils.py
  • BIN
      utils/error/response_utils.pyc
  • 0 0
      utils/redis/__init__.py
  • BIN
      utils/redis/__init__.pyc
  • 6 0
      utils/redis/connect.py
  • BIN
      utils/redis/connect.pyc
  • 68 0
      utils/redis/rkeys.py
  • + 29 - 0
    .editorconfig

    @@ -0,0 +1,29 @@
    1
    +# EditorConfig is awesome: http://EditorConfig.org
    2
    +
    3
    +# top-most EditorConfig file
    4
    +root = true
    5
    +
    6
    +# Unix-style newlines with a newline ending every file
    7
    +[*]
    8
    +end_of_line = lf
    9
    +insert_final_newline = false
    10
    +
    11
    +# 4 space indentation
    12
    +[*.py]
    13
    +indent_style = space
    14
    +indent_size = 4
    15
    +
    16
    +# Tab indentation (no size specified)
    17
    +[*.js]
    18
    +indent_style = space
    19
    +indent_size = 4
    20
    +
    21
    +# Tab indentation (no size specified)
    22
    +[*.html]
    23
    +indent_style = space
    24
    +indent_size = 4
    25
    +
    26
    +# Matches the exact files either package.json or .travis.yml
    27
    +[{package.json,.travis.yml}]
    28
    +indent_style = space
    29
    +indent_size = 2

    + 14 - 0
    .idea/misc.xml

    @@ -0,0 +1,14 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    4
    +    <OptionsSetting value="true" id="Add" />
    5
    +    <OptionsSetting value="true" id="Remove" />
    6
    +    <OptionsSetting value="true" id="Checkout" />
    7
    +    <OptionsSetting value="true" id="Update" />
    8
    +    <OptionsSetting value="true" id="Status" />
    9
    +    <OptionsSetting value="true" id="Edit" />
    10
    +    <ConfirmationsSetting value="0" id="Add" />
    11
    +    <ConfirmationsSetting value="0" id="Remove" />
    12
    +  </component>
    13
    +  <component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.12+ (/usr/bin/python2.7)" project-jdk-type="Python SDK" />
    14
    +</project>

    + 8 - 0
    .idea/modules.xml

    @@ -0,0 +1,8 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ProjectModuleManager">
    4
    +    <modules>
    5
    +      <module fileurl="file://$PROJECT_DIR$/.idea/tamron.iml" filepath="$PROJECT_DIR$/.idea/tamron.iml" />
    6
    +    </modules>
    7
    +  </component>
    8
    +</project>

    + 26 - 0
    .idea/tamron.iml

    @@ -0,0 +1,26 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<module type="PYTHON_MODULE" version="4">
    3
    +  <component name="FacetManager">
    4
    +    <facet type="django" name="Django">
    5
    +      <configuration>
    6
    +        <option name="rootFolder" value="$MODULE_DIR$" />
    7
    +        <option name="settingsModule" value="tamron/settings.py" />
    8
    +        <option name="manageScript" value="manage.py" />
    9
    +        <option name="environment" value="&lt;map/&gt;" />
    10
    +        <option name="commandsToSkip" value="" />
    11
    +      </configuration>
    12
    +    </facet>
    13
    +  </component>
    14
    +  <component name="NewModuleRootManager">
    15
    +    <content url="file://$MODULE_DIR$" />
    16
    +    <orderEntry type="inheritedJdk" />
    17
    +    <orderEntry type="sourceFolder" forTests="false" />
    18
    +  </component>
    19
    +  <component name="TemplatesService">
    20
    +    <option name="TEMPLATE_CONFIGURATION" value="Django" />
    21
    +  </component>
    22
    +  <component name="TestRunnerService">
    23
    +    <option name="projectConfiguration" value="py.test" />
    24
    +    <option name="PROJECT_TEST_RUNNER" value="py.test" />
    25
    +  </component>
    26
    +</module>

    + 634 - 0
    .idea/workspace.xml

    @@ -0,0 +1,634 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ChangeListManager">
    4
    +    <list default="true" id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
    5
    +    <ignored path="tamron.iws" />
    6
    +    <ignored path=".idea/workspace.xml" />
    7
    +    <ignored path=".idea/dataSources.local.xml" />
    8
    +    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    9
    +    <option name="TRACKING_ENABLED" value="true" />
    10
    +    <option name="SHOW_DIALOG" value="false" />
    11
    +    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    12
    +    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    13
    +    <option name="LAST_RESOLUTION" value="IGNORE" />
    14
    +  </component>
    15
    +  <component name="CreatePatchCommitExecutor">
    16
    +    <option name="PATCH_PATH" value="" />
    17
    +  </component>
    18
    +  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
    19
    +  <component name="FavoritesManager">
    20
    +    <favorites_list name="tamron" />
    21
    +  </component>
    22
    +  <component name="FileEditorManager">
    23
    +    <leaf>
    24
    +      <file leaf-file-name="tamron.ini" pinned="false" current-in-tab="false">
    25
    +        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
    26
    +          <provider selected="true" editor-type-id="text-editor">
    27
    +            <state relative-caret-position="255">
    28
    +              <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
    29
    +              <folding />
    30
    +            </state>
    31
    +          </provider>
    32
    +        </entry>
    33
    +      </file>
    34
    +      <file leaf-file-name="tamron_nginx.conf" pinned="false" current-in-tab="true">
    35
    +        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
    36
    +          <provider selected="true" editor-type-id="text-editor">
    37
    +            <state relative-caret-position="480">
    38
    +              <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
    39
    +              <folding />
    40
    +            </state>
    41
    +          </provider>
    42
    +        </entry>
    43
    +      </file>
    44
    +    </leaf>
    45
    +  </component>
    46
    +  <component name="FileTemplateManagerImpl">
    47
    +    <option name="RECENT_TEMPLATES">
    48
    +      <list>
    49
    +        <option value="Python Script" />
    50
    +      </list>
    51
    +    </option>
    52
    +  </component>
    53
    +  <component name="IdeDocumentHistory">
    54
    +    <option name="CHANGED_PATHS">
    55
    +      <list>
    56
    +        <option value="$PROJECT_DIR$/tamron/basemodels.py" />
    57
    +        <option value="$PROJECT_DIR$/account/admin.py" />
    58
    +        <option value="$PROJECT_DIR$/product/admin.py" />
    59
    +        <option value="$PROJECT_DIR$/integral/admin.py" />
    60
    +        <option value="$PROJECT_DIR$/page/views.py" />
    61
    +        <option value="$PROJECT_DIR$/product/models.py" />
    62
    +        <option value="$PROJECT_DIR$/integral/models.py" />
    63
    +        <option value="$PROJECT_DIR$/tamron/settings.py" />
    64
    +        <option value="$PROJECT_DIR$/api/urls.py" />
    65
    +        <option value="$PROJECT_DIR$/tamron/local_settings.py" />
    66
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_oauth.html" />
    67
    +        <option value="$PROJECT_DIR$/page/sale_views.py" />
    68
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_sale.html" />
    69
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_into.html" />
    70
    +        <option value="$PROJECT_DIR$/tamron/urls.py" />
    71
    +        <option value="$PROJECT_DIR$/page/info_views.py" />
    72
    +        <option value="$PROJECT_DIR$/utils/error/errno_utils.py" />
    73
    +        <option value="$PROJECT_DIR$/page/oauth_views.py" />
    74
    +        <option value="$PROJECT_DIR$/account/models.py" />
    75
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_info.html" />
    76
    +        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini" />
    77
    +        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf" />
    78
    +      </list>
    79
    +    </option>
    80
    +  </component>
    81
    +  <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
    82
    +  <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
    83
    +  <component name="JsGulpfileManager">
    84
    +    <detection-done>true</detection-done>
    85
    +    <sorting>DEFINITION_ORDER</sorting>
    86
    +  </component>
    87
    +  <component name="ProjectFrameBounds">
    88
    +    <option name="x" value="65" />
    89
    +    <option name="y" value="24" />
    90
    +    <option name="width" value="1301" />
    91
    +    <option name="height" value="744" />
    92
    +  </component>
    93
    +  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    94
    +    <OptionsSetting value="true" id="Add" />
    95
    +    <OptionsSetting value="true" id="Remove" />
    96
    +    <OptionsSetting value="true" id="Checkout" />
    97
    +    <OptionsSetting value="true" id="Update" />
    98
    +    <OptionsSetting value="true" id="Status" />
    99
    +    <OptionsSetting value="true" id="Edit" />
    100
    +    <ConfirmationsSetting value="0" id="Add" />
    101
    +    <ConfirmationsSetting value="0" id="Remove" />
    102
    +  </component>
    103
    +  <component name="ProjectView">
    104
    +    <navigator currentView="ProjectPane" proportions="" version="1">
    105
    +      <flattenPackages />
    106
    +      <showMembers />
    107
    +      <showModules />
    108
    +      <showLibraryContents />
    109
    +      <hideEmptyPackages />
    110
    +      <abbreviatePackageNames />
    111
    +      <autoscrollToSource />
    112
    +      <autoscrollFromSource />
    113
    +      <sortByType />
    114
    +      <manualOrder />
    115
    +      <foldersAlwaysOnTop value="true" />
    116
    +    </navigator>
    117
    +    <panes>
    118
    +      <pane id="Scratches" />
    119
    +      <pane id="Scope" />
    120
    +      <pane id="ProjectPane">
    121
    +        <subPane>
    122
    +          <PATH>
    123
    +            <PATH_ELEMENT>
    124
    +              <option name="myItemId" value="tamron" />
    125
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
    126
    +            </PATH_ELEMENT>
    127
    +          </PATH>
    128
    +          <PATH>
    129
    +            <PATH_ELEMENT>
    130
    +              <option name="myItemId" value="tamron" />
    131
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
    132
    +            </PATH_ELEMENT>
    133
    +            <PATH_ELEMENT>
    134
    +              <option name="myItemId" value="tamron" />
    135
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
    136
    +            </PATH_ELEMENT>
    137
    +          </PATH>
    138
    +        </subPane>
    139
    +      </pane>
    140
    +    </panes>
    141
    +  </component>
    142
    +  <component name="PropertiesComponent">
    143
    +    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
    144
    +    <property name="WebServerToolWindowFactoryState" value="false" />
    145
    +    <property name="js-jscs-nodeInterpreter" value="$USER_HOME$/.nvm/versions/node/v6.10.0/bin/node" />
    146
    +  </component>
    147
    +  <component name="RecentsManager">
    148
    +    <key name="CopyFile.RECENT_KEYS">
    149
    +      <recent name="$PROJECT_DIR$/page" />
    150
    +      <recent name="$PROJECT_DIR$/page/templates/page" />
    151
    +    </key>
    152
    +  </component>
    153
    +  <component name="RunManager" selected="Django server.tamron">
    154
    +    <configuration default="true" type="DjangoTestsConfigurationType" factoryName="Django tests">
    155
    +      <option name="INTERPRETER_OPTIONS" value="" />
    156
    +      <option name="PARENT_ENVS" value="true" />
    157
    +      <envs>
    158
    +        <env name="PYTHONUNBUFFERED" value="1" />
    159
    +      </envs>
    160
    +      <option name="SDK_HOME" value="" />
    161
    +      <option name="WORKING_DIRECTORY" value="" />
    162
    +      <option name="IS_MODULE_SDK" value="false" />
    163
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    164
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    165
    +      <module name="tamron" />
    166
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    167
    +      <option name="TARGET" value="" />
    168
    +      <option name="SETTINGS_FILE" value="" />
    169
    +      <option name="CUSTOM_SETTINGS" value="false" />
    170
    +      <option name="USE_OPTIONS" value="false" />
    171
    +      <option name="OPTIONS" value="" />
    172
    +      <method />
    173
    +    </configuration>
    174
    +    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
    175
    +      <method />
    176
    +    </configuration>
    177
    +    <configuration default="true" type="PyBehaveRunConfigurationType" factoryName="Behave">
    178
    +      <option name="INTERPRETER_OPTIONS" value="" />
    179
    +      <option name="PARENT_ENVS" value="true" />
    180
    +      <envs />
    181
    +      <option name="SDK_HOME" value="" />
    182
    +      <option name="WORKING_DIRECTORY" value="" />
    183
    +      <option name="IS_MODULE_SDK" value="false" />
    184
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    185
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    186
    +      <module name="tamron" />
    187
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    188
    +      <option name="ADDITIONAL_ARGS" value="" />
    189
    +      <method />
    190
    +    </configuration>
    191
    +    <configuration default="true" type="PyLettuceRunConfigurationType" factoryName="Lettuce">
    192
    +      <option name="INTERPRETER_OPTIONS" value="" />
    193
    +      <option name="PARENT_ENVS" value="true" />
    194
    +      <envs />
    195
    +      <option name="SDK_HOME" value="" />
    196
    +      <option name="WORKING_DIRECTORY" value="" />
    197
    +      <option name="IS_MODULE_SDK" value="false" />
    198
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    199
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    200
    +      <module name="tamron" />
    201
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    202
    +      <option name="ADDITIONAL_ARGS" value="" />
    203
    +      <method />
    204
    +    </configuration>
    205
    +    <configuration default="true" type="Python.DjangoServer" factoryName="Django server">
    206
    +      <option name="INTERPRETER_OPTIONS" value="" />
    207
    +      <option name="PARENT_ENVS" value="true" />
    208
    +      <envs>
    209
    +        <env name="PYTHONUNBUFFERED" value="1" />
    210
    +      </envs>
    211
    +      <option name="SDK_HOME" value="" />
    212
    +      <option name="WORKING_DIRECTORY" value="" />
    213
    +      <option name="IS_MODULE_SDK" value="false" />
    214
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    215
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    216
    +      <module name="tamron" />
    217
    +      <option name="launchJavascriptDebuger" value="false" />
    218
    +      <option name="port" value="8000" />
    219
    +      <option name="host" value="" />
    220
    +      <option name="additionalOptions" value="" />
    221
    +      <option name="browserUrl" value="" />
    222
    +      <option name="runTestServer" value="false" />
    223
    +      <option name="runNoReload" value="false" />
    224
    +      <option name="useCustomRunCommand" value="false" />
    225
    +      <option name="customRunCommand" value="" />
    226
    +      <method />
    227
    +    </configuration>
    228
    +    <configuration default="true" type="PythonConfigurationType" factoryName="Python">
    229
    +      <option name="INTERPRETER_OPTIONS" value="" />
    230
    +      <option name="PARENT_ENVS" value="true" />
    231
    +      <envs>
    232
    +        <env name="PYTHONUNBUFFERED" value="1" />
    233
    +      </envs>
    234
    +      <option name="SDK_HOME" value="" />
    235
    +      <option name="WORKING_DIRECTORY" value="" />
    236
    +      <option name="IS_MODULE_SDK" value="false" />
    237
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    238
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    239
    +      <module name="tamron" />
    240
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    241
    +      <option name="SCRIPT_NAME" value="" />
    242
    +      <option name="PARAMETERS" value="" />
    243
    +      <option name="SHOW_COMMAND_LINE" value="false" />
    244
    +      <method />
    245
    +    </configuration>
    246
    +    <configuration default="true" type="Tox" factoryName="Tox">
    247
    +      <option name="INTERPRETER_OPTIONS" value="" />
    248
    +      <option name="PARENT_ENVS" value="true" />
    249
    +      <envs />
    250
    +      <option name="SDK_HOME" value="" />
    251
    +      <option name="WORKING_DIRECTORY" value="" />
    252
    +      <option name="IS_MODULE_SDK" value="false" />
    253
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    254
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    255
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    256
    +      <module name="tamron" />
    257
    +      <method />
    258
    +    </configuration>
    259
    +    <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
    260
    +      <node-interpreter>project</node-interpreter>
    261
    +      <node-options />
    262
    +      <gulpfile />
    263
    +      <tasks />
    264
    +      <arguments />
    265
    +      <envs />
    266
    +      <method />
    267
    +    </configuration>
    268
    +    <configuration default="true" type="js.build_tools.npm" factoryName="npm">
    269
    +      <command value="run-script" />
    270
    +      <scripts />
    271
    +      <node-interpreter value="project" />
    272
    +      <envs />
    273
    +      <method />
    274
    +    </configuration>
    275
    +    <configuration default="true" type="tests" factoryName="Attests">
    276
    +      <option name="INTERPRETER_OPTIONS" value="" />
    277
    +      <option name="PARENT_ENVS" value="true" />
    278
    +      <envs />
    279
    +      <option name="SDK_HOME" value="" />
    280
    +      <option name="WORKING_DIRECTORY" value="" />
    281
    +      <option name="IS_MODULE_SDK" value="false" />
    282
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    283
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    284
    +      <module name="tamron" />
    285
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    286
    +      <option name="SCRIPT_NAME" value="" />
    287
    +      <option name="CLASS_NAME" value="" />
    288
    +      <option name="METHOD_NAME" value="" />
    289
    +      <option name="FOLDER_NAME" value="" />
    290
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    291
    +      <option name="PATTERN" value="" />
    292
    +      <option name="USE_PATTERN" value="false" />
    293
    +      <method />
    294
    +    </configuration>
    295
    +    <configuration default="true" type="tests" factoryName="Doctests">
    296
    +      <option name="INTERPRETER_OPTIONS" value="" />
    297
    +      <option name="PARENT_ENVS" value="true" />
    298
    +      <envs />
    299
    +      <option name="SDK_HOME" value="" />
    300
    +      <option name="WORKING_DIRECTORY" value="" />
    301
    +      <option name="IS_MODULE_SDK" value="false" />
    302
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    303
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    304
    +      <module name="tamron" />
    305
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    306
    +      <option name="SCRIPT_NAME" value="" />
    307
    +      <option name="CLASS_NAME" value="" />
    308
    +      <option name="METHOD_NAME" value="" />
    309
    +      <option name="FOLDER_NAME" value="" />
    310
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    311
    +      <option name="PATTERN" value="" />
    312
    +      <option name="USE_PATTERN" value="false" />
    313
    +      <method />
    314
    +    </configuration>
    315
    +    <configuration default="true" type="tests" factoryName="Nosetests">
    316
    +      <option name="INTERPRETER_OPTIONS" value="" />
    317
    +      <option name="PARENT_ENVS" value="true" />
    318
    +      <envs />
    319
    +      <option name="SDK_HOME" value="" />
    320
    +      <option name="WORKING_DIRECTORY" value="" />
    321
    +      <option name="IS_MODULE_SDK" value="false" />
    322
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    323
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    324
    +      <module name="tamron" />
    325
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    326
    +      <option name="SCRIPT_NAME" value="" />
    327
    +      <option name="CLASS_NAME" value="" />
    328
    +      <option name="METHOD_NAME" value="" />
    329
    +      <option name="FOLDER_NAME" value="" />
    330
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    331
    +      <option name="PATTERN" value="" />
    332
    +      <option name="USE_PATTERN" value="false" />
    333
    +      <option name="PARAMS" value="" />
    334
    +      <option name="USE_PARAM" value="false" />
    335
    +      <method />
    336
    +    </configuration>
    337
    +    <configuration default="true" type="tests" factoryName="Unittests">
    338
    +      <option name="INTERPRETER_OPTIONS" value="" />
    339
    +      <option name="PARENT_ENVS" value="true" />
    340
    +      <envs />
    341
    +      <option name="SDK_HOME" value="" />
    342
    +      <option name="WORKING_DIRECTORY" value="" />
    343
    +      <option name="IS_MODULE_SDK" value="false" />
    344
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    345
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    346
    +      <module name="tamron" />
    347
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    348
    +      <option name="SCRIPT_NAME" value="" />
    349
    +      <option name="CLASS_NAME" value="" />
    350
    +      <option name="METHOD_NAME" value="" />
    351
    +      <option name="FOLDER_NAME" value="" />
    352
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    353
    +      <option name="PATTERN" value="" />
    354
    +      <option name="USE_PATTERN" value="false" />
    355
    +      <option name="PUREUNITTEST" value="true" />
    356
    +      <option name="PARAMS" value="" />
    357
    +      <option name="USE_PARAM" value="false" />
    358
    +      <method />
    359
    +    </configuration>
    360
    +    <configuration default="true" type="tests" factoryName="py.test">
    361
    +      <option name="INTERPRETER_OPTIONS" value="" />
    362
    +      <option name="PARENT_ENVS" value="true" />
    363
    +      <envs />
    364
    +      <option name="SDK_HOME" value="" />
    365
    +      <option name="WORKING_DIRECTORY" value="" />
    366
    +      <option name="IS_MODULE_SDK" value="false" />
    367
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    368
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    369
    +      <module name="tamron" />
    370
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    371
    +      <option name="SCRIPT_NAME" value="" />
    372
    +      <option name="CLASS_NAME" value="" />
    373
    +      <option name="METHOD_NAME" value="" />
    374
    +      <option name="FOLDER_NAME" value="" />
    375
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    376
    +      <option name="PATTERN" value="" />
    377
    +      <option name="USE_PATTERN" value="false" />
    378
    +      <option name="testToRun" value="" />
    379
    +      <option name="keywords" value="" />
    380
    +      <option name="params" value="" />
    381
    +      <option name="USE_PARAM" value="false" />
    382
    +      <option name="USE_KEYWORD" value="false" />
    383
    +      <method />
    384
    +    </configuration>
    385
    +    <configuration default="false" name="tamron" type="Python.DjangoServer" factoryName="Django server">
    386
    +      <option name="INTERPRETER_OPTIONS" value="" />
    387
    +      <option name="PARENT_ENVS" value="true" />
    388
    +      <envs>
    389
    +        <env name="PYTHONUNBUFFERED" value="1" />
    390
    +      </envs>
    391
    +      <option name="SDK_HOME" value="" />
    392
    +      <option name="WORKING_DIRECTORY" value="" />
    393
    +      <option name="IS_MODULE_SDK" value="false" />
    394
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    395
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    396
    +      <module name="tamron" />
    397
    +      <option name="launchJavascriptDebuger" value="false" />
    398
    +      <option name="port" value="8000" />
    399
    +      <option name="host" value="" />
    400
    +      <option name="additionalOptions" value="" />
    401
    +      <option name="browserUrl" value="" />
    402
    +      <option name="runTestServer" value="false" />
    403
    +      <option name="runNoReload" value="false" />
    404
    +      <option name="useCustomRunCommand" value="false" />
    405
    +      <option name="customRunCommand" value="" />
    406
    +      <method />
    407
    +    </configuration>
    408
    +    <list size="1">
    409
    +      <item index="0" class="java.lang.String" itemvalue="Django server.tamron" />
    410
    +    </list>
    411
    +  </component>
    412
    +  <component name="ShelveChangesManager" show_recycled="false">
    413
    +    <option name="remove_strategy" value="false" />
    414
    +  </component>
    415
    +  <component name="TaskManager">
    416
    +    <task active="true" id="Default" summary="Default task">
    417
    +      <changelist id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
    418
    +      <created>1497849391019</created>
    419
    +      <option name="number" value="Default" />
    420
    +      <option name="presentableId" value="Default" />
    421
    +      <updated>1497849391019</updated>
    422
    +    </task>
    423
    +    <servers />
    424
    +  </component>
    425
    +  <component name="ToolWindowManager">
    426
    +    <frame x="65" y="24" width="1301" height="744" extended-state="6" />
    427
    +    <editor active="false" />
    428
    +    <layout>
    429
    +      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.16756341" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
    430
    +      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
    431
    +      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
    432
    +      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
    433
    +      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    434
    +      <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    435
    +      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    436
    +      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    437
    +      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
    438
    +      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
    439
    +      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
    440
    +      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
    441
    +      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
    442
    +      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
    443
    +      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
    444
    +      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    445
    +      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    446
    +      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
    447
    +    </layout>
    448
    +  </component>
    449
    +  <component name="Vcs.Log.UiProperties">
    450
    +    <option name="RECENTLY_FILTERED_USER_GROUPS">
    451
    +      <collection />
    452
    +    </option>
    453
    +    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
    454
    +      <collection />
    455
    +    </option>
    456
    +  </component>
    457
    +  <component name="VcsContentAnnotationSettings">
    458
    +    <option name="myLimit" value="2678400000" />
    459
    +  </component>
    460
    +  <component name="XDebuggerManager">
    461
    +    <breakpoint-manager>
    462
    +      <option name="time" value="2" />
    463
    +    </breakpoint-manager>
    464
    +    <watches-manager />
    465
    +  </component>
    466
    +  <component name="editorHistoryManager">
    467
    +    <entry file="file://$PROJECT_DIR$/page/models.py">
    468
    +      <provider selected="true" editor-type-id="text-editor">
    469
    +        <state relative-caret-position="0">
    470
    +          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
    471
    +        </state>
    472
    +      </provider>
    473
    +    </entry>
    474
    +    <entry file="file://$PROJECT_DIR$/account/admin.py">
    475
    +      <provider selected="true" editor-type-id="text-editor">
    476
    +        <state relative-caret-position="165">
    477
    +          <caret line="13" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="23" selection-end-column="0" />
    478
    +        </state>
    479
    +      </provider>
    480
    +    </entry>
    481
    +    <entry file="file://$PROJECT_DIR$/tamron/basemodels.py">
    482
    +      <provider selected="true" editor-type-id="text-editor">
    483
    +        <state relative-caret-position="105">
    484
    +          <caret line="7" column="94" selection-start-line="7" selection-start-column="79" selection-end-line="7" selection-end-column="94" />
    485
    +        </state>
    486
    +      </provider>
    487
    +    </entry>
    488
    +    <entry file="file://$PROJECT_DIR$/integral/admin.py">
    489
    +      <provider selected="true" editor-type-id="text-editor">
    490
    +        <state relative-caret-position="150">
    491
    +          <caret line="10" column="38" selection-start-line="10" selection-start-column="38" selection-end-line="10" selection-end-column="38" />
    492
    +        </state>
    493
    +      </provider>
    494
    +    </entry>
    495
    +    <entry file="file://$PROJECT_DIR$/product/admin.py">
    496
    +      <provider selected="true" editor-type-id="text-editor">
    497
    +        <state relative-caret-position="390">
    498
    +          <caret line="26" column="0" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="60" />
    499
    +        </state>
    500
    +      </provider>
    501
    +    </entry>
    502
    +    <entry file="file://$PROJECT_DIR$/integral/views.py">
    503
    +      <provider selected="true" editor-type-id="text-editor">
    504
    +        <state relative-caret-position="60">
    505
    +          <caret line="4" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
    506
    +        </state>
    507
    +      </provider>
    508
    +    </entry>
    509
    +    <entry file="file://$PROJECT_DIR$/page/views.py">
    510
    +      <provider selected="true" editor-type-id="text-editor">
    511
    +        <state relative-caret-position="60">
    512
    +          <caret line="4" column="0" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
    513
    +        </state>
    514
    +      </provider>
    515
    +    </entry>
    516
    +    <entry file="file://$PROJECT_DIR$/product/models.py">
    517
    +      <provider selected="true" editor-type-id="text-editor">
    518
    +        <state relative-caret-position="308">
    519
    +          <caret line="43" column="104" selection-start-line="43" selection-start-column="104" selection-end-line="43" selection-end-column="104" />
    520
    +        </state>
    521
    +      </provider>
    522
    +    </entry>
    523
    +    <entry file="file://$PROJECT_DIR$/integral/models.py">
    524
    +      <provider selected="true" editor-type-id="text-editor">
    525
    +        <state relative-caret-position="360">
    526
    +          <caret line="24" column="30" selection-start-line="24" selection-start-column="30" selection-end-line="24" selection-end-column="30" />
    527
    +        </state>
    528
    +      </provider>
    529
    +    </entry>
    530
    +    <entry file="file://$PROJECT_DIR$/tamron/settings.py">
    531
    +      <provider selected="true" editor-type-id="text-editor">
    532
    +        <state relative-caret-position="312">
    533
    +          <caret line="200" column="6" selection-start-line="200" selection-start-column="0" selection-end-line="200" selection-end-column="6" />
    534
    +          <folding />
    535
    +        </state>
    536
    +      </provider>
    537
    +    </entry>
    538
    +    <entry file="file://$PROJECT_DIR$/tamron/local_settings.py">
    539
    +      <provider selected="true" editor-type-id="text-editor">
    540
    +        <state relative-caret-position="420">
    541
    +          <caret line="28" column="32" selection-start-line="28" selection-start-column="32" selection-end-line="28" selection-end-column="32" />
    542
    +        </state>
    543
    +      </provider>
    544
    +    </entry>
    545
    +    <entry file="file://$PROJECT_DIR$/api/urls.py">
    546
    +      <provider selected="true" editor-type-id="text-editor">
    547
    +        <state relative-caret-position="120">
    548
    +          <caret line="8" column="44" selection-start-line="8" selection-start-column="44" selection-end-line="8" selection-end-column="44" />
    549
    +        </state>
    550
    +      </provider>
    551
    +    </entry>
    552
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_oauth.html">
    553
    +      <provider selected="true" editor-type-id="text-editor">
    554
    +        <state relative-caret-position="360">
    555
    +          <caret line="57" column="18" selection-start-line="25" selection-start-column="12" selection-end-line="57" selection-end-column="18" />
    556
    +          <folding />
    557
    +        </state>
    558
    +      </provider>
    559
    +    </entry>
    560
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_sale.html">
    561
    +      <provider selected="true" editor-type-id="text-editor">
    562
    +        <state relative-caret-position="273">
    563
    +          <caret line="160" column="0" selection-start-line="160" selection-start-column="0" selection-end-line="160" selection-end-column="0" />
    564
    +          <folding />
    565
    +        </state>
    566
    +      </provider>
    567
    +    </entry>
    568
    +    <entry file="file://$PROJECT_DIR$/utils/error/errno_utils.py">
    569
    +      <provider selected="true" editor-type-id="text-editor">
    570
    +        <state relative-caret-position="75">
    571
    +          <caret line="5" column="26" selection-start-line="5" selection-start-column="6" selection-end-line="5" selection-end-column="26" />
    572
    +        </state>
    573
    +      </provider>
    574
    +    </entry>
    575
    +    <entry file="file://$PROJECT_DIR$/account/models.py">
    576
    +      <provider selected="true" editor-type-id="text-editor">
    577
    +        <state relative-caret-position="521">
    578
    +          <caret line="88" column="38" selection-start-line="88" selection-start-column="38" selection-end-line="88" selection-end-column="38" />
    579
    +        </state>
    580
    +      </provider>
    581
    +    </entry>
    582
    +    <entry file="file://$PROJECT_DIR$/tamron/urls.py">
    583
    +      <provider selected="true" editor-type-id="text-editor">
    584
    +        <state relative-caret-position="465">
    585
    +          <caret line="31" column="55" selection-start-line="31" selection-start-column="55" selection-end-line="31" selection-end-column="55" />
    586
    +        </state>
    587
    +      </provider>
    588
    +    </entry>
    589
    +    <entry file="file://$PROJECT_DIR$/page/sale_views.py">
    590
    +      <provider selected="true" editor-type-id="text-editor">
    591
    +        <state relative-caret-position="311">
    592
    +          <caret line="97" column="18" selection-start-line="97" selection-start-column="10" selection-end-line="97" selection-end-column="18" />
    593
    +        </state>
    594
    +      </provider>
    595
    +    </entry>
    596
    +    <entry file="file://$PROJECT_DIR$/page/info_views.py">
    597
    +      <provider selected="true" editor-type-id="text-editor">
    598
    +        <state relative-caret-position="300">
    599
    +          <caret line="20" column="42" selection-start-line="20" selection-start-column="42" selection-end-line="20" selection-end-column="42" />
    600
    +        </state>
    601
    +      </provider>
    602
    +    </entry>
    603
    +    <entry file="file://$PROJECT_DIR$/page/oauth_views.py">
    604
    +      <provider selected="true" editor-type-id="text-editor">
    605
    +        <state relative-caret-position="135">
    606
    +          <caret line="9" column="37" selection-start-line="9" selection-start-column="31" selection-end-line="9" selection-end-column="37" />
    607
    +        </state>
    608
    +      </provider>
    609
    +    </entry>
    610
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_info.html">
    611
    +      <provider selected="true" editor-type-id="text-editor">
    612
    +        <state relative-caret-position="48">
    613
    +          <caret line="44" column="0" selection-start-line="44" selection-start-column="0" selection-end-line="44" selection-end-column="0" />
    614
    +        </state>
    615
    +      </provider>
    616
    +    </entry>
    617
    +    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
    618
    +      <provider selected="true" editor-type-id="text-editor">
    619
    +        <state relative-caret-position="255">
    620
    +          <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
    621
    +          <folding />
    622
    +        </state>
    623
    +      </provider>
    624
    +    </entry>
    625
    +    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
    626
    +      <provider selected="true" editor-type-id="text-editor">
    627
    +        <state relative-caret-position="480">
    628
    +          <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
    629
    +          <folding />
    630
    +        </state>
    631
    +      </provider>
    632
    +    </entry>
    633
    +  </component>
    634
    +</project>

    + 8 - 0
    .isort.cfg

    @@ -0,0 +1,8 @@
    1
    +# See the menu of settings available here:
    2
    +#   https://github.com/timothycrosley/isort/wiki/isort-Settings
    3
    +
    4
    +[settings]
    5
    +indent='    '
    6
    +line_length=120
    7
    +lines_after_imports=2
    8
    +skip=migrations

    + 0 - 0
    account/__init__.py


    BIN
    account/__init__.pyc


    + 23 - 0
    account/admin.py

    @@ -0,0 +1,23 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from account.models import FranchiserInfo, SaleclerkInfo
    6
    +
    7
    +
    8
    +class FranchiserInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('franchiser_id', )
    10
    +    list_display = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone')
    12
    +    list_filter = ('status', )
    13
    +
    14
    +
    15
    +class SaleclerkInfoAdmin(admin.ModelAdmin):
    16
    +    readonly_fields = ('franchiser_id', )
    17
    +    list_display = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_sex', 'clerk_phone', 'user_status', 'status', 'created_at', 'updated_at')
    18
    +    search_fields = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_phone')
    19
    +    list_filter = ('user_status', 'status')
    20
    +
    21
    +
    22
    +admin.site.register(FranchiserInfo, FranchiserInfoAdmin)
    23
    +admin.site.register(SaleclerkInfo, SaleclerkInfoAdmin)

    BIN
    account/admin.pyc


    + 55 - 0
    account/migrations/0001_initial.py

    @@ -0,0 +1,55 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +import shortuuidfield.fields
    6
    +
    7
    +
    8
    +class Migration(migrations.Migration):
    9
    +
    10
    +    dependencies = [
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.CreateModel(
    15
    +            name='FranchiserInfo',
    16
    +            fields=[
    17
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    18
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    19
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    20
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    21
    +                ('franchiser_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    22
    +                ('franchiser_name', models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True)),
    23
    +                ('franchiser_addr', models.CharField(help_text='\u7ecf\u9500\u5546\u5730\u5740', max_length=255, null=True, verbose_name='franchiser_addr', blank=True)),
    24
    +                ('franchiser_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_phone', blank=True)),
    25
    +                ('franchiser_boss_name', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_boss_name', blank=True)),
    26
    +                ('franchiser_boss_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_boss_phone', blank=True)),
    27
    +            ],
    28
    +            options={
    29
    +                'verbose_name': 'franchiserinfo',
    30
    +                'verbose_name_plural': 'franchiserinfo',
    31
    +            },
    32
    +        ),
    33
    +        migrations.CreateModel(
    34
    +            name='SaleclerkInfo',
    35
    +            fields=[
    36
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    37
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    38
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    39
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    40
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    41
    +                ('clerk_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    42
    +                ('clerk_name', models.CharField(help_text='\u5e97\u5458\u540d\u79f0', max_length=255, null=True, verbose_name='clerk_name', blank=True)),
    43
    +                ('clerk_sex', models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    44
    +                ('clerk_phone', models.CharField(help_text='\u5e97\u5458\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='clerk_phone', blank=True)),
    45
    +                ('openid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 OpenID', unique=True, verbose_name='openid', db_index=True)),
    46
    +                ('unionid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 UnionID', unique=True, verbose_name='unionid', db_index=True)),
    47
    +                ('user_status', models.IntegerField(default=0, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')])),
    48
    +                ('refused_reason', models.TextField(help_text='\u5ba1\u6838\u62d2\u7edd\u539f\u56e0', null=True, verbose_name='refused_reason', blank=True)),
    49
    +            ],
    50
    +            options={
    51
    +                'verbose_name': 'saleclerkinfo',
    52
    +                'verbose_name_plural': 'saleclerkinfo',
    53
    +            },
    54
    +        ),
    55
    +    ]

    BIN
    account/migrations/0001_initial.pyc


    + 33 - 0
    account/migrations/0002_auto_20170619_1635.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('account', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterModelOptions(
    15
    +            name='franchiserinfo',
    16
    +            options={'verbose_name': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868', 'verbose_name_plural': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868'},
    17
    +        ),
    18
    +        migrations.AddField(
    19
    +            model_name='saleclerkinfo',
    20
    +            name='integral',
    21
    +            field=models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral'),
    22
    +        ),
    23
    +        migrations.AlterField(
    24
    +            model_name='saleclerkinfo',
    25
    +            name='clerk_sex',
    26
    +            field=models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', db_index=True, verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')]),
    27
    +        ),
    28
    +        migrations.AlterField(
    29
    +            model_name='saleclerkinfo',
    30
    +            name='user_status',
    31
    +            field=models.IntegerField(default=0, help_text='\u7528\u6237\u72b6\u6001', db_index=True, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')]),
    32
    +        ),
    33
    +    ]

    BIN
    account/migrations/0002_auto_20170619_1635.pyc


    + 19 - 0
    account/migrations/0003_saleclerkinfo_franchiser_name.py

    @@ -0,0 +1,19 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('account', '0002_auto_20170619_1635'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AddField(
    15
    +            model_name='saleclerkinfo',
    16
    +            name='franchiser_name',
    17
    +            field=models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True),
    18
    +        ),
    19
    +    ]

    BIN
    account/migrations/0003_saleclerkinfo_franchiser_name.pyc


    + 0 - 0
    account/migrations/__init__.py


    BIN
    account/migrations/__init__.pyc


    + 92 - 0
    account/models.py

    @@ -0,0 +1,92 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +from shortuuidfield import ShortUUIDField
    6
    +
    7
    +from tamron.basemodels import CreateUpdateMixin
    8
    +
    9
    +
    10
    +class FranchiserInfo(CreateUpdateMixin):
    11
    +    franchiser_id = ShortUUIDField(_(u'franchiser_id'), max_length=255, help_text=u'经销商唯一标识', db_index=True, unique=True)
    12
    +    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
    13
    +    franchiser_addr = models.CharField(_(u'franchiser_addr'), max_length=255, blank=True, null=True, help_text=u'经销商地址')
    14
    +    franchiser_phone = models.CharField(_(u'franchiser_phone'), max_length=255, blank=True, null=True, help_text=u'经销商联系电话')
    15
    +    franchiser_boss_name = models.CharField(_(u'franchiser_boss_name'), max_length=255, blank=True, null=True, help_text=u'经销商老板名称')
    16
    +    franchiser_boss_phone = models.CharField(_(u'franchiser_boss_phone'), max_length=255, blank=True, null=True, help_text=u'经销商老板联系电话')
    17
    +
    18
    +    class Meta:
    19
    +        verbose_name = _(u'经销商信息表')
    20
    +        verbose_name_plural = _(u'经销商信息表')
    21
    +
    22
    +    def __unicode__(self):
    23
    +        return unicode(self.pk)
    24
    +
    25
    +    @property
    26
    +    def data(self):
    27
    +        return {
    28
    +            'franchiser_id': self.franchiser_id,
    29
    +            'franchiser_name': self.franchiser_name,
    30
    +        }
    31
    +
    32
    +
    33
    +class SaleclerkInfo(CreateUpdateMixin):
    34
    +    MALE = 1
    35
    +    FEMALE = 0
    36
    +
    37
    +    SEX_TYPE = (
    38
    +        (MALE, u'男'),
    39
    +        (FEMALE, u'女'),
    40
    +    )
    41
    +
    42
    +    REFUSED = -1
    43
    +    UNVERIFIED = 0
    44
    +    ACTIVATED = 1
    45
    +    DISABLED = 2
    46
    +    DELETED = 3
    47
    +    ASSIGN = 10
    48
    +
    49
    +    USER_STATUS = (
    50
    +        (REFUSED, u'已拒绝'),
    51
    +        (UNVERIFIED, u'未验证'),
    52
    +        (ACTIVATED, u'已激活'),
    53
    +        (DISABLED, u'已禁用'),
    54
    +        (DELETED, u'已删除'),
    55
    +        (ASSIGN, u'已分配'),
    56
    +    )
    57
    +
    58
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    59
    +    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
    60
    +    clerk_id = ShortUUIDField(_(u'clerk_id'), max_length=255, help_text=u'店员唯一标识', db_index=True, unique=True)
    61
    +    clerk_name = models.CharField(_(u'clerk_name'), max_length=255, blank=True, null=True, help_text=u'店员名称')
    62
    +    clerk_sex = models.IntegerField(_(u'clerk_sex'), choices=SEX_TYPE, default=MALE, help_text=u'店员性别', db_index=True)
    63
    +    clerk_phone = models.CharField(_(u'clerk_phone'), max_length=255, blank=True, null=True, help_text=u'店员联系电话')
    64
    +
    65
    +    openid = models.CharField(_(u'openid'), max_length=255, blank=True, null=True, help_text=u'微信 OpenID', db_index=True, unique=True)
    66
    +    unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 UnionID', db_index=True, unique=True)
    67
    +
    68
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
    69
    +
    70
    +    user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED, help_text=u'用户状态', db_index=True)
    71
    +    refused_reason = models.TextField(_(u'refused_reason'), blank=True, null=True, help_text=u'审核拒绝原因')
    72
    +
    73
    +    class Meta:
    74
    +        verbose_name = _(u'saleclerkinfo')
    75
    +        verbose_name_plural = _(u'saleclerkinfo')
    76
    +
    77
    +    def __unicode__(self):
    78
    +        return unicode(self.pk)
    79
    +
    80
    +    @property
    81
    +    def data(self):
    82
    +        return {
    83
    +            'franchiser_id': self.franchiser_id,
    84
    +            'franchiser_name': self.franchiser_name,
    85
    +            'clerk_id': self.clerk_id,
    86
    +            'clerk_name': self.clerk_name,
    87
    +            'clerk_sex': self.clerk_sex,
    88
    +            'clerk_phone': self.clerk_phone,
    89
    +            'integral': self.integral,
    90
    +            'status': self.user_status,
    91
    +            'refused_reason': self.refused_reason,
    92
    +        }

    BIN
    account/models.pyc


    + 4 - 0
    account/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    account/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 0 - 0
    api/__init__.py


    BIN
    api/__init__.pyc


    + 4 - 0
    api/admin.py

    @@ -0,0 +1,4 @@
    1
    +from django.contrib import admin
    2
    +
    3
    +
    4
    +# Register your models here.

    BIN
    api/admin.pyc


    + 0 - 0
    api/migrations/__init__.py


    BIN
    api/migrations/__init__.pyc


    + 4 - 0
    api/models.py

    @@ -0,0 +1,4 @@
    1
    +from django.db import models
    2
    +
    3
    +
    4
    +# Create your models here.

    BIN
    api/models.pyc


    + 4 - 0
    api/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 11 - 0
    api/urls.py

    @@ -0,0 +1,11 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.conf.urls import url
    4
    +
    5
    +from page import oauth_views, sale_views
    6
    +
    7
    +
    8
    +urlpatterns = [
    9
    +    url(r'^clerk/submit$', oauth_views.clerk_submit_api, name='clerk_submit_api'),  # 店员信息提交
    10
    +    url(r'^clerk/sale/submit$', sale_views.clerk_sale_submit_api, name='clerk_sale_submit_api'),  # 店员销售信息提交
    11
    +]

    BIN
    api/urls.pyc


    + 4 - 0
    api/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 9 - 0
    check.sh

    @@ -0,0 +1,9 @@
    1
    +#!/bin/bash
    2
    +
    3
    +echo '>> iSort'
    4
    +./isort.sh
    5
    +echo
    6
    +
    7
    +echo '>> PEP8'
    8
    +./pep8.sh
    9
    +echo

    + 0 - 0
    integral/__init__.py


    BIN
    integral/__init__.pyc


    + 15 - 0
    integral/admin.py

    @@ -0,0 +1,15 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from integral.models import SaleclerkIntegralIncomeExpensesInfo
    6
    +
    7
    +
    8
    +class SaleclerkIntegralIncomeExpensesInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral')
    10
    +    list_display = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral', 'remark', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('code', 'remark')
    12
    +    list_filter = ('franchiser_id', 'type', 'status')
    13
    +
    14
    +
    15
    +admin.site.register(SaleclerkIntegralIncomeExpensesInfo, SaleclerkIntegralIncomeExpensesInfoAdmin)

    BIN
    integral/admin.pyc


    + 33 - 0
    integral/migrations/0001_initial.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +    ]
    11
    +
    12
    +    operations = [
    13
    +        migrations.CreateModel(
    14
    +            name='SaleclerkIntegralIncomeExpensesInfo',
    15
    +            fields=[
    16
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    17
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    18
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    19
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    20
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    21
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    22
    +                ('type', models.IntegerField(default=0, help_text='\u6536\u652f\u7c7b\u522b', db_index=True, verbose_name='type', choices=[(0, '\u6536\u5165'), (1, '\u652f\u51fa'), (2, '\u89e3\u51bb')])),
    23
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    24
    +                ('integral', models.IntegerField(default=0, help_text='\u589e\u51cf\u79ef\u5206', verbose_name='integral')),
    25
    +                ('left_integral', models.IntegerField(default=0, help_text='\u79ef\u5206\u589e\u51cf\u540e\u6570\u91cf(\u5206)', verbose_name='left_integral')),
    26
    +                ('remark', models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True)),
    27
    +            ],
    28
    +            options={
    29
    +                'verbose_name': 'saleclerkintegralincomeexpensesinfo',
    30
    +                'verbose_name_plural': 'saleclerkintegralincomeexpensesinfo',
    31
    +            },
    32
    +        ),
    33
    +    ]

    BIN
    integral/migrations/0001_initial.pyc


    + 19 - 0
    integral/migrations/0002_auto_20170619_1734.py

    @@ -0,0 +1,19 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('integral', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterField(
    15
    +            model_name='saleclerkintegralincomeexpensesinfo',
    16
    +            name='code',
    17
    +            field=models.CharField(max_length=255, blank=True, help_text='\u673a\u8eab\u7801', null=True, verbose_name='code', db_index=True),
    18
    +        ),
    19
    +    ]

    BIN
    integral/migrations/0002_auto_20170619_1734.pyc


    + 0 - 0
    integral/migrations/__init__.py


    BIN
    integral/migrations/__init__.pyc


    + 36 - 0
    integral/models.py

    @@ -0,0 +1,36 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +
    6
    +from tamron.basemodels import CreateUpdateMixin
    7
    +
    8
    +
    9
    +class SaleclerkIntegralIncomeExpensesInfo(CreateUpdateMixin):
    10
    +    INCOME = 0
    11
    +    EXPENSE = 1
    12
    +    UNFREEZE = 2
    13
    +
    14
    +    TYPE = (
    15
    +        (INCOME, u'收入'),
    16
    +        (EXPENSE, u'支出'),
    17
    +        (UNFREEZE, u'解冻'),
    18
    +    )
    19
    +
    20
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    21
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    22
    +
    23
    +    type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别', db_index=True)
    24
    +
    25
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码', db_index=True)
    26
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'增减积分')
    27
    +    left_integral = models.IntegerField(_(u'left_integral'), default=0, help_text=u'积分增减后数量(分)')
    28
    +
    29
    +    remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')
    30
    +
    31
    +    class Meta:
    32
    +        verbose_name = _(u'saleclerkintegralincomeexpensesinfo')
    33
    +        verbose_name_plural = _(u'saleclerkintegralincomeexpensesinfo')
    34
    +
    35
    +    def __unicode__(self):
    36
    +        return unicode(self.pk)

    BIN
    integral/models.pyc


    + 4 - 0
    integral/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    integral/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 3 - 0
    isort.sh

    @@ -0,0 +1,3 @@
    1
    +#!/bin/bash
    2
    +
    3
    +isort -rc -sp . .

    + 11 - 0
    manage.py

    @@ -0,0 +1,11 @@
    1
    +#!/usr/bin/env python
    2
    +import os
    3
    +import sys
    4
    +
    5
    +
    6
    +if __name__ == "__main__":
    7
    +    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
    8
    +
    9
    +    from django.core.management import execute_from_command_line
    10
    +
    11
    +    execute_from_command_line(sys.argv)

    + 0 - 0
    page/__init__.py


    BIN
    page/__init__.pyc


    + 4 - 0
    page/admin.py

    @@ -0,0 +1,4 @@
    1
    +from django.contrib import admin
    2
    +
    3
    +
    4
    +# Register your models here.

    BIN
    page/admin.pyc


    + 22 - 0
    page/info_views.py

    @@ -0,0 +1,22 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.shortcuts import render
    7
    +
    8
    +from account.models import SaleclerkInfo
    9
    +
    10
    +
    11
    +def clerk_info_oauth(request):
    12
    +    unionid = request.GET.get('unionid', '')
    13
    +
    14
    +    try:
    15
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    16
    +    except SaleclerkInfo.DoesNotExist:
    17
    +        clerk = None
    18
    +
    19
    +    return render(request, 'page/clerk_info.html', {
    20
    +        'domain': settings.DOMAIN,
    21
    +        'clerk_info': clerk and clerk.data,
    22
    +    })

    BIN
    page/info_views.pyc


    + 0 - 0
    page/migrations/__init__.py


    BIN
    page/migrations/__init__.pyc


    + 4 - 0
    page/models.py

    @@ -0,0 +1,4 @@
    1
    +from django.db import models
    2
    +
    3
    +
    4
    +# Create your models here.

    BIN
    page/models.pyc


    + 70 - 0
    page/oauth_views.py

    @@ -0,0 +1,70 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.db import transaction
    7
    +from django.shortcuts import render
    8
    +from logit import logit
    9
    +
    10
    +from account.models import FranchiserInfo, SaleclerkInfo
    11
    +from utils.error.errno_utils import FranchiserStatusCode, SaleclerkStatusCode
    12
    +from utils.error.response_utils import response
    13
    +
    14
    +
    15
    +def clerk_oauth(request):
    16
    +    unionid = request.GET.get('unionid', '')
    17
    +
    18
    +    chisers = FranchiserInfo.objects.filter(status=True)
    19
    +    chisers = [chiser.data for chiser in chisers]
    20
    +
    21
    +    try:
    22
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    23
    +    except SaleclerkInfo.DoesNotExist:
    24
    +        clerk = None
    25
    +
    26
    +    return render(request, 'page/clerk_oauth.html', {
    27
    +        'domain': settings.DOMAIN,
    28
    +        'chisers': chisers,
    29
    +        'clerk_info': clerk and clerk.data,
    30
    +        'modified': bool((not clerk) or (clerk and clerk.user_status in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED])),  # 是否可以更改信息
    31
    +    })
    32
    +
    33
    +
    34
    +@logit
    35
    +@transaction.atomic
    36
    +def clerk_submit_api(request):
    37
    +    """ 店员授权信息提交 """
    38
    +    unionid = request.POST.get('unionid', '')
    39
    +    openid = request.POST.get('openid', '')
    40
    +    phone = request.POST.get('phone', '')
    41
    +    chiser = request.POST.get('chiser', '')
    42
    +
    43
    +    if SaleclerkInfo.objects.filter(clerk_phone=phone).exclude(unionid=unionid).exists():
    44
    +        return response(SaleclerkStatusCode.CLERK_PHONE_ALREADY_EXISTS)
    45
    +
    46
    +    try:
    47
    +        franchiser = FranchiserInfo.objects.get(franchiser_id=chiser)
    48
    +    except FranchiserInfo.DoesNotExist:
    49
    +        return response(FranchiserStatusCode.CHISER_NOT_FOUND)
    50
    +
    51
    +    fields = {
    52
    +        'franchiser_id': chiser,
    53
    +        'franchiser_name': franchiser.franchiser_name,
    54
    +        'clerk_name': request.POST.get('name', ''),
    55
    +        'clerk_sex': int(request.POST.get('sex', 1)),
    56
    +        'clerk_phone': phone,
    57
    +        'openid': openid,
    58
    +        'user_status': SaleclerkInfo.UNVERIFIED,
    59
    +    }
    60
    +
    61
    +    lensman, created = SaleclerkInfo.objects.select_for_update().get_or_create(unionid=unionid, defaults=fields)
    62
    +    # 状态为 UNVERIFIED 的允许修改, 其他需要登录摄影师 APP 进行信息的修改
    63
    +    if lensman.user_status not in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED]:
    64
    +        return response(SaleclerkInfo.LENSMAN_ALREADY_NOT_UNVERIFIED)
    65
    +    if not created:
    66
    +        for key, value in fields.iteritems():
    67
    +            setattr(lensman, key, value)
    68
    +        lensman.save()
    69
    +
    70
    +    return response(200, 'Submit Success', u'提交成功', {})

    BIN
    page/oauth_views.pyc


    + 111 - 0
    page/sale_views.py

    @@ -0,0 +1,111 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.db import transaction
    7
    +from django.shortcuts import render
    8
    +from logit import logit
    9
    +
    10
    +from account.models import SaleclerkInfo
    11
    +from integral.models import SaleclerkIntegralIncomeExpensesInfo
    12
    +from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
    13
    +from utils.error.errno_utils import ProductModelStatusCode, ProductStatusCode, SaleclerkStatusCode
    14
    +from utils.error.response_utils import response
    15
    +
    16
    +
    17
    +def clerk_sale_oauth(request):
    18
    +    unionid = request.GET.get('unionid', '')
    19
    +
    20
    +    models = ProductModelInfo.objects.filter(status=True)
    21
    +    models = [model.data for model in models]
    22
    +
    23
    +    try:
    24
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    25
    +    except SaleclerkInfo.DoesNotExist:
    26
    +        clerk = None
    27
    +
    28
    +    return render(request, 'page/clerk_sale.html', {
    29
    +        'domain': settings.DOMAIN,
    30
    +        'models': models,
    31
    +        'clerk_info': clerk and clerk.data,
    32
    +    })
    33
    +
    34
    +
    35
    +@logit
    36
    +@transaction.atomic
    37
    +def clerk_sale_submit_api(request):
    38
    +    """ 店员信息提交 """
    39
    +    clerk_id = request.POST.get('clerk_id', '')
    40
    +    model_id = request.POST.get('model_id', '')
    41
    +    code = request.POST.get('code', '')
    42
    +    name = request.POST.get('name', '')
    43
    +    sex = int(request.POST.get('sex', 1))
    44
    +    age = int(request.POST.get('age', 1))
    45
    +    phone = request.POST.get('phone', '')
    46
    +
    47
    +    # 店员是否存在
    48
    +    try:
    49
    +        clerk = SaleclerkInfo.objects.select_for_update().get(clerk_id=clerk_id)
    50
    +    except SaleclerkInfo.DoesNotExist:
    51
    +        return response(SaleclerkStatusCode.CLERK_NOT_FOUND)
    52
    +
    53
    +    # 店员是否激活
    54
    +    if clerk.user_status != SaleclerkInfo.ACTIVATED:
    55
    +        return response(SaleclerkStatusCode.CLERK_NOT_ACTIVATED)
    56
    +
    57
    +    # 型号是否存在
    58
    +    try:
    59
    +        model = ProductModelInfo.objects.get(model_id=model_id)
    60
    +    except ProductModelInfo.DoesNotExist:
    61
    +        return response(ProductModelStatusCode.MODEL_NOT_FOUND)
    62
    +
    63
    +    # 记录销售提交记录
    64
    +    ProductCodeSubmitLogInfo.objects.create(
    65
    +        model_id=model.model_id,
    66
    +        model_name=model.model_name,
    67
    +        code=code,
    68
    +        franchiser_id=clerk.franchiser_id,
    69
    +        clerk_id=clerk.clerk_id,
    70
    +        consumer_name=name,
    71
    +        consumer_sex=sex,
    72
    +        consumer_age=age,
    73
    +        consumer_phone=phone,
    74
    +    )
    75
    +
    76
    +    # 产品是否存在
    77
    +    try:
    78
    +        product = ProductInfo.objects.select_for_update().get(model_id=model_id, code=code)
    79
    +    except ProductInfo.DoesNotExist:
    80
    +        return response(ProductStatusCode.PRODUCT_NOT_FOUND)
    81
    +
    82
    +    # 产品是否使用
    83
    +    if product.code_status:
    84
    +        return response(ProductStatusCode.PRODUCT_HAS_USED)
    85
    +
    86
    +    # 产品使用
    87
    +    product.code_status = True
    88
    +    product.integral_status = True
    89
    +    product.franchiser_id = clerk.franchiser_id
    90
    +    product.clerk_id = clerk.clerk_id
    91
    +    product.consumer_name = name
    92
    +    product.consumer_sex = sex
    93
    +    product.consumer_age = age
    94
    +    product.consumer_phone = phone
    95
    +    product.save()
    96
    +
    97
    +    # 店员积分
    98
    +    clerk.integral += product.integral
    99
    +    clerk.save()
    100
    +
    101
    +    # 店员积分记录
    102
    +    SaleclerkIntegralIncomeExpensesInfo.objects.create(
    103
    +        franchiser_id=clerk.franchiser_id,
    104
    +        clerk_id=clerk.clerk_id,
    105
    +        type=SaleclerkIntegralIncomeExpensesInfo.INCOME,
    106
    +        code=code,
    107
    +        integral=product.integral,
    108
    +        left_integral=clerk.integral,
    109
    +    )
    110
    +
    111
    +    return response(200, 'Submit Success', u'提交成功', {})

    BIN
    page/sale_views.pyc


    + 74 - 0
    page/templates/page/clerk_info.html

    @@ -0,0 +1,74 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员销售</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">基本信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <input id="chiser" class="weui_input" type="text" value="{{ clerk_info.franchiser_name }}" disabled>
    31
    +                    </div>
    32
    +                </div>
    33
    +                <div class="weui_cell">
    34
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    35
    +                    <div class="weui_cell_bd weui_cell_primary">
    36
    +                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" disabled>
    37
    +                    </div>
    38
    +                </div>
    39
    +                <div class="weui_cell">
    40
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    41
    +                    <div class="weui_cell_bd weui_cell_primary">
    42
    +                        <input id="sex" class="weui_input" type="text" value="{% ifequal clerk_info.clerk_sex 1 %}男{% else %}女{% endifequal %}" disabled>
    43
    +                    </div>
    44
    +                </div>
    45
    +                <div class="weui_cell">
    46
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    47
    +                    <div class="weui_cell_bd weui_cell_primary">
    48
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" disabled>
    49
    +                    </div>
    50
    +                </div>
    51
    +                <div class="weui_cell">
    52
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">积分</label></div>
    53
    +                    <div class="weui_cell_bd weui_cell_primary">
    54
    +                        <input id="integral" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.integral }}" disabled>
    55
    +                    </div>
    56
    +                </div>
    57
    +            </div>
    58
    +        </div>
    59
    +
    60
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    61
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    62
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    63
    +        <script>
    64
    +            V.initWxData({
    65
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    66
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    67
    +                desc: "摄影师授权",
    68
    +                title: "摄影师授权",
    69
    +                timeLine: ""
    70
    +            }, true);
    71
    +            V.hideOptionMenu();
    72
    +        </script>
    73
    +    </body>
    74
    +</html>

    + 198 - 0
    page/templates/page/clerk_oauth.html

    @@ -0,0 +1,198 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员授权</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">基本信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell weui_cell_select weui_select_after">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">经销商</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <select id="chiser" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
    31
    +                            {% for chiser in chisers %}
    32
    +                            <option value="{{ chiser.franchiser_id }}" {% ifequal chiser.franchiser_id clerk_info.franchiser_id %}selected{% endifequal %}>{{ chiser.franchiser_name }}</option>
    33
    +                            {% endfor %}
    34
    +                        </select>
    35
    +                    </div>
    36
    +                </div>
    37
    +                <div class="weui_cell">
    38
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    39
    +                    <div class="weui_cell_bd weui_cell_primary">
    40
    +                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" placeholder="请输入姓名" {% if not modified %}disabled{% endif %}>
    41
    +                    </div>
    42
    +                </div>
    43
    +                <div class="weui_cell weui_cell_select weui_select_after">
    44
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
    45
    +                    <div class="weui_cell_bd weui_cell_primary">
    46
    +                        <select id="sex" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
    47
    +                            <option value="1" {% ifequal clerk_info.clerk_sex 1 %}selected{% endifequal %}>男</option>
    48
    +                            <option value="0" {% ifequal clerk_info.clerk_sex 0 %}selected{% endifequal %}>女</option>
    49
    +                        </select>
    50
    +                    </div>
    51
    +                </div>
    52
    +                <div class="weui_cell">
    53
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    54
    +                    <div class="weui_cell_bd weui_cell_primary">
    55
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" placeholder="请输入手机号" {% if not modified %}disabled{% endif %}>
    56
    +                    </div>
    57
    +                </div>
    58
    +            </div>
    59
    +
    60
    +            {% if clerk_info %}
    61
    +            <div class="weui_cells_title">审核状态</div>
    62
    +            <div class="weui_cells">
    63
    +                <div class="weui_cell">
    64
    +                    <div class="weui_cell_bd weui_cell_primary">
    65
    +                        <p>状态</p>
    66
    +                    </div>
    67
    +                    <div class="weui_cell_ft">
    68
    +                        {% ifequal clerk_info.status -1 %}已拒绝{% endifequal %}
    69
    +                        {% ifequal clerk_info.status 0 %}审核中{% endifequal %}
    70
    +                        {% ifequal clerk_info.status 1 %}已激活{% endifequal %}
    71
    +                        {% ifequal clerk_info.status 2 %}已禁用{% endifequal %}
    72
    +                        {% ifequal clerk_info.status 3 %}已删除{% endifequal %}
    73
    +                    </div>
    74
    +                </div>
    75
    +            </div>
    76
    +            {% endif %}
    77
    +
    78
    +
    79
    +            {% ifequal clerk_info.status -1 %}
    80
    +            <div class="weui_cells_title">拒绝原因</div>
    81
    +            <div class="weui_cells">
    82
    +                <div class="weui_panel_bd">
    83
    +                    <div class="weui_media_box weui_media_text">
    84
    +                        <p class="weui_media_desc">{{ clerk_info.refused_reason|safe|linebreaks }}</p>
    85
    +                    </div>
    86
    +                </div>
    87
    +            </div>
    88
    +            {% endifequal %}
    89
    +
    90
    +            <br>
    91
    +
    92
    +            {% if modified %}<button id="submit" class="weui_btn weui_btn_warn">确认</button>{% endif %}
    93
    +
    94
    +            <div class="weui_dialog_alert" id="dialog" style="display: none">
    95
    +                <div class="weui_mask"></div>
    96
    +                <div class="weui_dialog">
    97
    +                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
    98
    +                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
    99
    +                    <div class="weui_dialog_ft">
    100
    +                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
    101
    +                    </div>
    102
    +                </div>
    103
    +            </div>
    104
    +
    105
    +            <div id="toast" style="display: none;">
    106
    +                <div class="weui_mask_transparent"></div>
    107
    +                <div class="weui_toast">
    108
    +                    <i class="weui_icon_toast"></i>
    109
    +                    <p class="weui_toast_content">已完成</p>
    110
    +                </div>
    111
    +            </div>
    112
    +        </div>
    113
    +
    114
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    115
    +        <script>
    116
    +            {% if modified %}
    117
    +            $(function() {
    118
    +                function getURLParameter(name) {
    119
    +                  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
    120
    +                }
    121
    +
    122
    +                function show_error_dialog(title, content) {
    123
    +                    $('#dialog #title').text(title);
    124
    +                    $('#dialog #content').text(content);
    125
    +                    $('#dialog').show();
    126
    +                }
    127
    +
    128
    +                function data_check() {
    129
    +                    var unionid = getURLParameter('unionid');
    130
    +                    if (!unionid) {
    131
    +                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
    132
    +                        return false;
    133
    +                    }
    134
    +
    135
    +                    var name = $('#name').val();
    136
    +                    if (!name) {
    137
    +                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
    138
    +                        return false;
    139
    +                    }
    140
    +
    141
    +                    var phone_valid = $('#phone').is(':valid');
    142
    +                    if (!phone_valid) {
    143
    +                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
    144
    +                        return false;
    145
    +                    }
    146
    +
    147
    +                    return {
    148
    +                        unionid: unionid,
    149
    +                        openid: getURLParameter('openid'),
    150
    +                        chiser: $('#chiser option:checked').val(),
    151
    +                        name: name,
    152
    +                        sex: $('#sex option:checked').val(),
    153
    +                        phone: $('#phone').val(),
    154
    +                    }
    155
    +                }
    156
    +
    157
    +                $('#submit').click(function () {
    158
    +                    var check_result = data_check();
    159
    +                    if (check_result){
    160
    +                        $.ajax({
    161
    +                            type: 'POST',
    162
    +                            url: '{{ domain }}api/clerk/submit',
    163
    +                            data: check_result,
    164
    +                            success: function(data) {
    165
    +                                if (data.status == 200) {
    166
    +                                    $('#toast').show();
    167
    +                                    setTimeout(function () {
    168
    +                                        $('#toast').hide();
    169
    +                                    }, 1000);
    170
    +                                    window.location.reload();
    171
    +                                } else {
    172
    +                                    show_error_dialog('错误', data.description);
    173
    +                                }
    174
    +                            }
    175
    +                        })
    176
    +                    }
    177
    +                });
    178
    +
    179
    +                $('#dialog .weui_btn_dialog').click(function () {
    180
    +                    $('#dialog').hide();
    181
    +                })
    182
    +            });
    183
    +            {% endif %}
    184
    +        </script>
    185
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    186
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    187
    +        <script>
    188
    +            V.initWxData({
    189
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    190
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    191
    +                desc: "摄影师授权",
    192
    +                title: "摄影师授权",
    193
    +                timeLine: ""
    194
    +            }, true);
    195
    +            V.hideOptionMenu();
    196
    +        </script>
    197
    +    </body>
    198
    +</html>

    + 187 - 0
    page/templates/page/clerk_sale.html

    @@ -0,0 +1,187 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员销售</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">机器信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell weui_cell_select weui_select_after">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">型号</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <select id="model" class="weui_select" name="select">
    31
    +                            {% for model in models %}
    32
    +                            <option value="{{ model.model_id }}">{{ model.model_name }}</option>
    33
    +                            {% endfor %}
    34
    +                        </select>
    35
    +                    </div>
    36
    +                </div>
    37
    +                <div class="weui_cell">
    38
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">机身码</label></div>
    39
    +                    <div class="weui_cell_bd weui_cell_primary">
    40
    +                        <input id="code" class="weui_input" type="text" value="" placeholder="请输入机身码">
    41
    +                    </div>
    42
    +                </div>
    43
    +            </div>
    44
    +
    45
    +            <div class="weui_cells_title">消费者信息</div>
    46
    +            <div class="weui_cells weui_cells_form">
    47
    +                <div class="weui_cell">
    48
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    49
    +                    <div class="weui_cell_bd weui_cell_primary">
    50
    +                        <input id="name" class="weui_input" type="text" value="" placeholder="请输入消费者姓名">
    51
    +                    </div>
    52
    +                </div>
    53
    +                <div class="weui_cell weui_cell_select weui_select_after">
    54
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
    55
    +                    <div class="weui_cell_bd weui_cell_primary">
    56
    +                        <select id="sex" class="weui_select" name="select">
    57
    +                            <option value="1">男</option>
    58
    +                            <option value="0">女</option>
    59
    +                        </select>
    60
    +                    </div>
    61
    +                </div>
    62
    +                <div class="weui_cell weui_cell_select weui_select_after">
    63
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">年龄</label></div>
    64
    +                    <div class="weui_cell_bd weui_cell_primary">
    65
    +                        <select id="age" class="weui_select" name="select">
    66
    +                            <option value="1">18周岁以下</option>
    67
    +                            <option value="2">60周岁以上</option>
    68
    +                        </select>
    69
    +                    </div>
    70
    +                </div>
    71
    +                <div class="weui_cell">
    72
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    73
    +                    <div class="weui_cell_bd weui_cell_primary">
    74
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="" placeholder="请输入消费者手机号">
    75
    +                    </div>
    76
    +                </div>
    77
    +            </div>
    78
    +
    79
    +            <br>
    80
    +
    81
    +            <button id="submit" class="weui_btn weui_btn_warn">确认</button>
    82
    +
    83
    +            <div class="weui_dialog_alert" id="dialog" style="display: none">
    84
    +                <div class="weui_mask"></div>
    85
    +                <div class="weui_dialog">
    86
    +                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
    87
    +                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
    88
    +                    <div class="weui_dialog_ft">
    89
    +                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
    90
    +                    </div>
    91
    +                </div>
    92
    +            </div>
    93
    +
    94
    +            <div id="toast" style="display: none;">
    95
    +                <div class="weui_mask_transparent"></div>
    96
    +                <div class="weui_toast">
    97
    +                    <i class="weui_icon_toast"></i>
    98
    +                    <p class="weui_toast_content">已完成</p>
    99
    +                </div>
    100
    +            </div>
    101
    +        </div>
    102
    +
    103
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    104
    +        <script>
    105
    +            $(function() {
    106
    +                function show_error_dialog(title, content) {
    107
    +                    $('#dialog #title').text(title);
    108
    +                    $('#dialog #content').text(content);
    109
    +                    $('#dialog').show();
    110
    +                }
    111
    +
    112
    +                function data_check() {
    113
    +                    var clerk_id = "{{ clerk_info.clerk_id }}";
    114
    +                    if (!clerk_id) {
    115
    +                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
    116
    +                        return false;
    117
    +                    }
    118
    +
    119
    +                    var code = $('#code').val();
    120
    +                    if (!code) {
    121
    +                        show_error_dialog('机身码', '机身码错误,请检查重新输入');
    122
    +                        return false;
    123
    +                    }
    124
    +
    125
    +                    var name = $('#name').val();
    126
    +                    if (!name) {
    127
    +                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
    128
    +                        return false;
    129
    +                    }
    130
    +
    131
    +                    var phone_valid = $('#phone').is(':valid');
    132
    +                    if (!phone_valid) {
    133
    +                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
    134
    +                        return false;
    135
    +                    }
    136
    +
    137
    +                    return {
    138
    +                        clerk_id: clerk_id,
    139
    +                        model_id: $('#model option:checked').val(),
    140
    +                        code: code,
    141
    +                        name: name,
    142
    +                        sex: $('#sex option:checked').val(),
    143
    +                        age: $('#age option:checked').val(),
    144
    +                        phone: $('#phone').val(),
    145
    +                    }
    146
    +                }
    147
    +
    148
    +                $('#submit').click(function () {
    149
    +                    var check_result = data_check();
    150
    +                    if (check_result){
    151
    +                        $.ajax({
    152
    +                            type: 'POST',
    153
    +                            url: '{{ domain }}api/clerk/sale/submit',
    154
    +                            data: check_result,
    155
    +                            success: function(data) {
    156
    +                                if (data.status == 200) {
    157
    +                                    $('#toast').show();
    158
    +                                    setTimeout(function () {
    159
    +                                        $('#toast').hide();
    160
    +                                    }, 1000);
    161
    +                                } else {
    162
    +                                    show_error_dialog('错误', data.description);
    163
    +                                }
    164
    +                            }
    165
    +                        })
    166
    +                    }
    167
    +                });
    168
    +
    169
    +                $('#dialog .weui_btn_dialog').click(function () {
    170
    +                    $('#dialog').hide();
    171
    +                })
    172
    +            });
    173
    +        </script>
    174
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    175
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    176
    +        <script>
    177
    +            V.initWxData({
    178
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    179
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    180
    +                desc: "摄影师授权",
    181
    +                title: "摄影师授权",
    182
    +                timeLine: ""
    183
    +            }, true);
    184
    +            V.hideOptionMenu();
    185
    +        </script>
    186
    +    </body>
    187
    +</html>

    + 4 - 0
    page/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    page/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    BIN
    page/views.pyc


    + 9 - 0
    pep8.sh

    @@ -0,0 +1,9 @@
    1
    +#!/bin/bash
    2
    +
    3
    +# Ignoring autogenerated files
    4
    +#  -- Migration directories
    5
    +# Ignoring error codes
    6
    +#  -- E128 continuation line under-indented for visual indent
    7
    +#  -- E501 line too long
    8
    +
    9
    +pep8 --exclude=migrations --ignore=E128,E501 .

    + 0 - 0
    product/__init__.py


    BIN
    product/__init__.pyc


    + 29 - 0
    product/admin.py

    @@ -0,0 +1,29 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
    6
    +
    7
    +
    8
    +class ProductModelInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('model_id', )
    10
    +    list_display = ('model_id', 'model_name', 'integral', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('model_id', 'model_name')
    12
    +    list_filter = ('status', )
    13
    +
    14
    +
    15
    +class ProductInfoAdmin(admin.ModelAdmin):
    16
    +    list_display = ('model_id', 'model_name', 'code', 'code_status', 'integral', 'integral_status', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
    17
    +    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
    18
    +    list_filter = ('code_status', 'integral_status', 'franchiser_id', 'consumer_sex', 'status')
    19
    +
    20
    +
    21
    +class ProductCodeSubmitLogInfoAdmin(admin.ModelAdmin):
    22
    +    list_display = ('model_id', 'model_name', 'code', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
    23
    +    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
    24
    +    list_filter = ('franchiser_id', 'consumer_sex', 'status')
    25
    +
    26
    +
    27
    +admin.site.register(ProductModelInfo, ProductModelInfoAdmin)
    28
    +admin.site.register(ProductInfo, ProductInfoAdmin)
    29
    +admin.site.register(ProductCodeSubmitLogInfo, ProductCodeSubmitLogInfoAdmin)

    BIN
    product/admin.pyc


    + 77 - 0
    product/migrations/0001_initial.py

    @@ -0,0 +1,77 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +import shortuuidfield.fields
    6
    +
    7
    +
    8
    +class Migration(migrations.Migration):
    9
    +
    10
    +    dependencies = [
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.CreateModel(
    15
    +            name='ProductCodeSubmitLogInfo',
    16
    +            fields=[
    17
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    18
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    19
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    20
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    21
    +                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
    22
    +                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
    23
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    24
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    25
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    26
    +                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
    27
    +                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    28
    +                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
    29
    +                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
    30
    +            ],
    31
    +            options={
    32
    +                'verbose_name': 'productcodesubmitloginfo',
    33
    +                'verbose_name_plural': 'productcodesubmitloginfo',
    34
    +            },
    35
    +        ),
    36
    +        migrations.CreateModel(
    37
    +            name='ProductInfo',
    38
    +            fields=[
    39
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    40
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    41
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    42
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    43
    +                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
    44
    +                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
    45
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    46
    +                ('code_status', models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001', db_index=True, verbose_name='code_status')),
    47
    +                ('integral', models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral')),
    48
    +                ('integral_status', models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001', db_index=True, verbose_name='integral_status')),
    49
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    50
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    51
    +                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
    52
    +                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    53
    +                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
    54
    +                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
    55
    +            ],
    56
    +            options={
    57
    +                'verbose_name': 'productinfo',
    58
    +                'verbose_name_plural': 'productinfo',
    59
    +            },
    60
    +        ),
    61
    +        migrations.CreateModel(
    62
    +            name='ProductModelInfo',
    63
    +            fields=[
    64
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    65
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    66
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    67
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    68
    +                ('model_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    69
    +                ('model_name', models.CharField(help_text='\u578b\u53f7\u540d\u79f0', max_length=255, null=True, verbose_name='model_name', blank=True)),
    70
    +                ('integral', models.IntegerField(default=0, help_text='\u578b\u53f7\u79ef\u5206', verbose_name='integral')),
    71
    +            ],
    72
    +            options={
    73
    +                'verbose_name': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
    74
    +                'verbose_name_plural': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
    75
    +            },
    76
    +        ),
    77
    +    ]

    BIN
    product/migrations/0001_initial.pyc


    + 24 - 0
    product/migrations/0002_auto_20170619_1734.py

    @@ -0,0 +1,24 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('product', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterField(
    15
    +            model_name='productinfo',
    16
    +            name='code_status',
    17
    +            field=models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001, True\u5df2\u4f7f\u7528\uff0cFalse\u672a\u4f7f\u7528', db_index=True, verbose_name='code_status'),
    18
    +        ),
    19
    +        migrations.AlterField(
    20
    +            model_name='productinfo',
    21
    +            name='integral_status',
    22
    +            field=models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001, True\u5df2\u79ef\u5206\uff0cFalse\u672a\u79ef\u5206', db_index=True, verbose_name='integral_status'),
    23
    +        ),
    24
    +    ]

    BIN
    product/migrations/0002_auto_20170619_1734.pyc


    + 0 - 0
    product/migrations/__init__.py


    BIN
    product/migrations/__init__.pyc


    + 99 - 0
    product/models.py

    @@ -0,0 +1,99 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +from shortuuidfield import ShortUUIDField
    6
    +
    7
    +from tamron.basemodels import CreateUpdateMixin
    8
    +
    9
    +
    10
    +class ProductModelInfo(CreateUpdateMixin):
    11
    +    model_id = ShortUUIDField(_(u'model_id'), max_length=255, help_text=u'型号唯一标识', db_index=True, unique=True)
    12
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称')
    13
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'型号积分')
    14
    +
    15
    +    class Meta:
    16
    +        verbose_name = _(u'产品型号信息')
    17
    +        verbose_name_plural = _(u'产品型号信息')
    18
    +
    19
    +    def __unicode__(self):
    20
    +        return unicode(self.pk)
    21
    +
    22
    +    @property
    23
    +    def data(self):
    24
    +        return {
    25
    +            'model_id': self.model_id,
    26
    +            'model_name': self.model_name,
    27
    +            'integral': self.integral,
    28
    +        }
    29
    +
    30
    +
    31
    +class ProductInfo(CreateUpdateMixin):
    32
    +    MALE = 1
    33
    +    FEMALE = 0
    34
    +
    35
    +    SEX_TYPE = (
    36
    +        (MALE, u'男'),
    37
    +        (FEMALE, u'女'),
    38
    +    )
    39
    +
    40
    +    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
    41
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
    42
    +
    43
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
    44
    +    code_status = models.BooleanField(_(u'code_status'), default=False, help_text=u'机身码状态, True已使用,False未使用', db_index=True)
    45
    +
    46
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
    47
    +    integral_status = models.BooleanField(_(u'integral_status'), default=False, help_text=u'积分状态, True已积分,False未积分', db_index=True)
    48
    +
    49
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    50
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    51
    +
    52
    +    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
    53
    +    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
    54
    +    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
    55
    +    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
    56
    +
    57
    +    class Meta:
    58
    +        verbose_name = _(u'productinfo')
    59
    +        verbose_name_plural = _(u'productinfo')
    60
    +
    61
    +    def __unicode__(self):
    62
    +        return unicode(self.pk)
    63
    +
    64
    +    @property
    65
    +    def data(self):
    66
    +        return {
    67
    +            'model_id': self.model_id,
    68
    +            'model_name': self.model_name,
    69
    +            'code': self.code,
    70
    +        }
    71
    +
    72
    +
    73
    +class ProductCodeSubmitLogInfo(CreateUpdateMixin):
    74
    +    MALE = 1
    75
    +    FEMALE = 0
    76
    +
    77
    +    SEX_TYPE = (
    78
    +        (MALE, u'男'),
    79
    +        (FEMALE, u'女'),
    80
    +    )
    81
    +
    82
    +    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
    83
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
    84
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
    85
    +
    86
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    87
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    88
    +
    89
    +    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
    90
    +    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
    91
    +    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
    92
    +    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
    93
    +
    94
    +    class Meta:
    95
    +        verbose_name = _(u'productcodesubmitloginfo')
    96
    +        verbose_name_plural = _(u'productcodesubmitloginfo')
    97
    +
    98
    +    def __unicode__(self):
    99
    +        return unicode(self.pk)

    BIN
    product/models.pyc


    + 4 - 0
    product/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    product/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 39 - 0
    requirements.txt

    @@ -0,0 +1,39 @@
    1
    +-e git+https://github.com/Brightcells/django-q.git#egg=django-q
    2
    +-e git+https://github.com/andymccurdy/redis-py.git#egg=redis-py
    3
    +CodeConvert==2.0.4
    4
    +Django==1.8.4
    5
    +MySQL-python==1.2.5
    6
    +Pillow==3.4.2
    7
    +StatusCode==1.0.0
    8
    +TimeConvert==1.4.1
    9
    +cryptography==1.5.2
    10
    +django-curtail-uuid==1.0.0
    11
    +django-detect==1.0.5
    12
    +django-file-md5==1.0.1
    13
    +django-ip==1.0.0
    14
    +django-json-response==1.1.4
    15
    +django-logit==1.0.6
    16
    +django-multidomain==1.1.4
    17
    +django-paginator2==1.0.3
    18
    +django-rlog==1.0.7
    19
    +django-shortuuidfield==0.1.3
    20
    +django-six==1.0.2
    21
    +djangorestframework==3.6.3
    22
    +furl==1.0.0
    23
    +hiredis==0.2.0
    24
    +isoweek==1.3.3
    25
    +jsonfield==2.0.2
    26
    +mock==2.0.0
    27
    +pep8==1.7.0
    28
    +pysnippets==1.0.4
    29
    +pywe-miniapp==1.0.0
    30
    +pywe-oauth==1.0.3
    31
    +pywe-response==1.0.1
    32
    +qiniu==7.1.4
    33
    +redis-extensions==1.0.50
    34
    +requests==2.12.4
    35
    +rlog==0.2
    36
    +shortuuid==0.5.0
    37
    +uWSGI==2.0.15
    38
    +versions==0.10.0
    39
    +wechatpy==1.2.8

    + 0 - 0
    tamron/__init__.py


    BIN
    tamron/__init__.pyc


    + 13 - 0
    tamron/basemodels.py

    @@ -0,0 +1,13 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +
    6
    +
    7
    +class CreateUpdateMixin(models.Model):
    8
    +    status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'), db_index=True)
    9
    +    created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))
    10
    +    updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))
    11
    +
    12
    +    class Meta:
    13
    +        abstract = True

    BIN
    tamron/basemodels.pyc


    + 16 - 0
    tamron/func_settings.py

    @@ -0,0 +1,16 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +import redis_extensions as redis
    4
    +
    5
    +
    6
    +def redis_conf(conf):
    7
    +    return {
    8
    +        'host': conf.get('HOST', 'localhost'),
    9
    +        'port': conf.get('PORT', 6379),
    10
    +        'password': '{}:{}'.format(conf.get('USER', ''), conf.get('PASSWORD', '')) if conf.get('USER') else '',
    11
    +        'db': conf.get('db', 0),
    12
    +    }
    13
    +
    14
    +
    15
    +def redis_connect(conf):
    16
    +    return redis.StrictRedisExtensions(connection_pool=redis.ConnectionPool(**redis_conf(conf)))

    BIN
    tamron/func_settings.pyc


    + 29 - 0
    tamron/local_settings.py

    @@ -0,0 +1,29 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +import os
    4
    +
    5
    +
    6
    +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    7
    +PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
    8
    +
    9
    +TEMPLATES = [
    10
    +    {
    11
    +        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    12
    +        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    13
    +        # 'APP_DIRS': True,
    14
    +        'OPTIONS': {
    15
    +            'context_processors': [
    16
    +                'django.template.context_processors.debug',
    17
    +                'django.template.context_processors.request',
    18
    +                'django.contrib.auth.context_processors.auth',
    19
    +                'django.contrib.messages.context_processors.messages',
    20
    +            ],
    21
    +            'loaders': [
    22
    +                'django.template.loaders.filesystem.Loader',
    23
    +                'django.template.loaders.app_directories.Loader',
    24
    +            ],
    25
    +        },
    26
    +    },
    27
    +]
    28
    +
    29
    +DOMAIN = 'http://127.0.0.1:9997/'

    BIN
    tamron/local_settings.pyc


    + 254 - 0
    tamron/settings.py

    @@ -0,0 +1,254 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +"""
    4
    +Django settings for tamron project.
    5
    +
    6
    +Generated by 'django-admin startproject' using Django 1.8.4.
    7
    +
    8
    +For more information on this file, see
    9
    +https://docs.djangoproject.com/en/1.8/topics/settings/
    10
    +
    11
    +For the full list of settings and their values, see
    12
    +https://docs.djangoproject.com/en/1.8/ref/settings/
    13
    +"""
    14
    +
    15
    +# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    16
    +import os
    17
    +
    18
    +
    19
    +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    20
    +PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
    21
    +
    22
    +
    23
    +# Quick-start development settings - unsuitable for production
    24
    +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
    25
    +
    26
    +# SECURITY WARNING: keep the secret key used in production secret!
    27
    +SECRET_KEY = '@!_8xi9(8)gj8zvni#)2-arn)4gn^u&coy-0yld0=1r5*ao@4i'
    28
    +
    29
    +# SECURITY WARNING: don't run with debug turned on in production!
    30
    +DEBUG = True
    31
    +
    32
    +ALLOWED_HOSTS = []
    33
    +
    34
    +
    35
    +# Application definition
    36
    +
    37
    +INSTALLED_APPS = (
    38
    +    'django.contrib.admin',
    39
    +    'django.contrib.auth',
    40
    +    'django.contrib.contenttypes',
    41
    +    'django.contrib.sessions',
    42
    +    'django.contrib.messages',
    43
    +    'django.contrib.staticfiles',
    44
    +    'api',
    45
    +    'account',
    46
    +    'integral',
    47
    +    'page',
    48
    +    'product',
    49
    +)
    50
    +
    51
    +MIDDLEWARE_CLASSES = (
    52
    +    'django.contrib.sessions.middleware.SessionMiddleware',
    53
    +    'django.middleware.common.CommonMiddleware',
    54
    +    # 'django.middleware.csrf.CsrfViewMiddleware',
    55
    +    'django.contrib.auth.middleware.AuthenticationMiddleware',
    56
    +    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    57
    +    'django.contrib.messages.middleware.MessageMiddleware',
    58
    +    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    59
    +    'django.middleware.security.SecurityMiddleware',
    60
    +)
    61
    +
    62
    +ROOT_URLCONF = 'tamron.urls'
    63
    +
    64
    +TEMPLATES = [
    65
    +    {
    66
    +        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    67
    +        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    68
    +        # 'APP_DIRS': True,
    69
    +        'OPTIONS': {
    70
    +            'context_processors': [
    71
    +                'django.template.context_processors.debug',
    72
    +                'django.template.context_processors.request',
    73
    +                'django.contrib.auth.context_processors.auth',
    74
    +                'django.contrib.messages.context_processors.messages',
    75
    +            ],
    76
    +            'loaders': [
    77
    +                ('django.template.loaders.cached.Loader', [
    78
    +                    'django.template.loaders.filesystem.Loader',
    79
    +                    'django.template.loaders.app_directories.Loader',
    80
    +                ]),
    81
    +            ],
    82
    +        },
    83
    +    },
    84
    +]
    85
    +
    86
    +WSGI_APPLICATION = 'tamron.wsgi.application'
    87
    +
    88
    +
    89
    +# Database
    90
    +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
    91
    +
    92
    +DATABASES = {
    93
    +    'default': {
    94
    +        'ENGINE': 'django.db.backends.mysql',
    95
    +        'NAME': 'tamron',
    96
    +        'USER': 'root',
    97
    +        'PASSWORD': '',
    98
    +        'CONN_MAX_AGE': 600,
    99
    +        'OPTIONS': {
    100
    +            # Utf8mb4 for Emoji
    101
    +            #
    102
    +            # Nickname
    103
    +            #
    104
    +            # account.WechatInfo ==> nickname
    105
    +            #   ALTER TABLE account_wechatinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    106
    +            # account.UserInfo ==> nickname
    107
    +            #   ALTER TABLE account_userinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    108
    +            # group.GroupUserInfo ==> nickname
    109
    +            #   ALTER TABLE group_groupuserinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    110
    +            # group.GroupPhotoInfo ==> nickname
    111
    +            #   ALTER TABLE group_groupphotoinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    112
    +            # group.PhotoCommentInfo ==> nickname
    113
    +            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    114
    +            # group.PhotoThumbUpInfo ==> nickname
    115
    +            #   ALTER TABLE group_photothumbupinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    116
    +            # group.UserMessageInfo ==> nickname
    117
    +            #   ALTER TABLE message_usermessageinfo MODIFY COLUMN from_nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    118
    +            #
    119
    +            # Comment
    120
    +            # group.PhotoCommentInfo ==> comment
    121
    +            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN comment LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    122
    +            'charset': 'utf8mb4',
    123
    +        },
    124
    +    }
    125
    +}
    126
    +
    127
    +
    128
    +# Internationalization
    129
    +# https://docs.djangoproject.com/en/1.8/topics/i18n/
    130
    +
    131
    +LANGUAGE_CODE = 'zh-Hans'
    132
    +
    133
    +TIME_ZONE = 'Asia/Shanghai'
    134
    +
    135
    +USE_I18N = True
    136
    +
    137
    +USE_L10N = True
    138
    +
    139
    +USE_TZ = True
    140
    +
    141
    +
    142
    +# Static files (CSS, JavaScript, Images)
    143
    +# https://docs.djangoproject.com/en/1.8/howto/static-files/
    144
    +
    145
    +STATICFILES_DIRS = (
    146
    +    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
    147
    +)
    148
    +
    149
    +STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
    150
    +
    151
    +STATIC_URL = '/static/'
    152
    +
    153
    +STATICFILES_FINDERS = (
    154
    +    'django.contrib.staticfiles.finders.FileSystemFinder',
    155
    +    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    156
    +    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
    157
    +)
    158
    +
    159
    +MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
    160
    +
    161
    +MEDIA_URL = '/media/'
    162
    +
    163
    +# Redis 设置
    164
    +REDIS = {
    165
    +    'default': {
    166
    +        'HOST': '127.0.0.1',
    167
    +        'PORT': 6379,
    168
    +        'USER': '',
    169
    +        'PASSWORD': '',
    170
    +        'db': 0,
    171
    +    }
    172
    +}
    173
    +
    174
    +# 微信设置
    175
    +WECHAT = {
    176
    +    'JSAPI': {
    177
    +        'token': '5201314',
    178
    +        'appID': '',
    179
    +        'appsecret': '',
    180
    +        'mchID': '',
    181
    +        'apiKey': '',
    182
    +        'mch_cert': '',
    183
    +        'mch_key': '',
    184
    +        'redpacket': {
    185
    +
    186
    +        }
    187
    +    },
    188
    +}
    189
    +
    190
    +# 微信授权设置
    191
    +WECHAT_BASE_REDIRECT_URI = 'https://api.pai.ai/base_redirect'
    192
    +WECHAT_USERINFO_REDIRECT_URI = 'https://api.pai.ai/userinfo_redirect'
    193
    +WECHAT_OAUTH2_RETRY_REDIRECT_URI = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
    194
    +
    195
    +WECHAT_OAUTH2_REDIRECT_URL = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
    196
    +
    197
    +# LOGIT 设置
    198
    +LOGIT_BODY_FLAG = True
    199
    +LOGIT_RES_FLAG = True
    200
    +
    201
    +DOMAIN = ''
    202
    +
    203
    +try:
    204
    +    from local_settings import *
    205
    +except ImportError:
    206
    +    pass
    207
    +
    208
    +try:
    209
    +    from func_settings import redis_connect
    210
    +    REDIS_CACHE = redis_connect(REDIS.get('default', {}))
    211
    +
    212
    +    DJLOGIT = {
    213
    +        'level': 'DEBUG',
    214
    +        'class': 'rlog.RedisListHandler',
    215
    +        'redis_client': REDIS_CACHE,
    216
    +        'key': 'django:logit:tamron',
    217
    +        'formatter': 'verbose',
    218
    +    }
    219
    +except ImportError:
    220
    +    REDIS_CACHE = None
    221
    +
    222
    +# 日志设置
    223
    +LOGGING = {
    224
    +    'version': 1,
    225
    +    'disable_existing_loggers': False,
    226
    +    'formatters': {
    227
    +        'verbose': {
    228
    +            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
    229
    +        },
    230
    +        'simple': {
    231
    +            'format': '%(levelname)s %(message)s'
    232
    +        },
    233
    +    },
    234
    +    'handlers': {
    235
    +        'logit': DJLOGIT,
    236
    +        'console': {
    237
    +            'level': 'DEBUG',
    238
    +            'class': 'logging.StreamHandler',
    239
    +            'formatter': 'verbose'
    240
    +        },
    241
    +    },
    242
    +    'loggers': {
    243
    +        'logit': {
    244
    +            'handlers': ['logit'],
    245
    +            'level': 'DEBUG',
    246
    +            'propagate': True,
    247
    +        },
    248
    +        'console': {
    249
    +            'handlers': ['console'],
    250
    +            'level': 'DEBUG',
    251
    +            'propagate': True,
    252
    +        },
    253
    +    },
    254
    +}

    BIN
    tamron/settings.pyc


    + 300 - 0
    tamron/static/tamron/js/jswe.js

    @@ -0,0 +1,300 @@
    1
    +!(function(e, t) {
    2
    +    var config = {
    3
    +        wxconfig: 'http://api.pai.ai/wx/jsapi_signature',
    4
    +        callback: 'callback'
    5
    +    }, wxData = {
    6
    +        debug: false,
    7
    +        imgUrl: '',
    8
    +        link: '',
    9
    +        desc: '',
    10
    +        title: '',
    11
    +        timeLine: ''
    12
    +    }, wxConfig = {
    13
    +        hide: false,
    14
    +        close: false
    15
    +    }, jsApiList = [
    16
    +        'checkJsApi',
    17
    +        'onMenuShareTimeline',
    18
    +        'onMenuShareAppMessage',
    19
    +        'onMenuShareQQ',
    20
    +        'onMenuShareWeibo',
    21
    +        'hideMenuItems',
    22
    +        'showMenuItems',
    23
    +        'hideAllNonBaseMenuItem',
    24
    +        'showAllNonBaseMenuItem',
    25
    +        'translateVoice',
    26
    +        'startRecord',
    27
    +        'stopRecord',
    28
    +        'onRecordEnd',
    29
    +        'playVoice',
    30
    +        'pauseVoice',
    31
    +        'stopVoice',
    32
    +        'uploadVoice',
    33
    +        'downloadVoice',
    34
    +        'chooseImage',
    35
    +        'previewImage',
    36
    +        'uploadImage',
    37
    +        'downloadImage',
    38
    +        'getNetworkType',
    39
    +        'openLocation',
    40
    +        'getLocation',
    41
    +        'hideOptionMenu',
    42
    +        'showOptionMenu',
    43
    +        'closeWindow',
    44
    +        'scanQRCode',
    45
    +        'chooseWXPay',
    46
    +        'openEnterpriseRedPacket',
    47
    +        'openProductSpecificView',
    48
    +        'addCard',
    49
    +        'chooseCard',
    50
    +        'openCard'
    51
    +    ], wxApiFun
    52
    +
    53
    +    function isOpenOnPC() {  // 判断当前网页是否在 PC 浏览器中打开
    54
    +        var ua = navigator.userAgent
    55
    +        return /windows nt/i.test(ua) || /macintosh/i.test(ua) || /linux x86_64/i.test(ua)
    56
    +    }
    57
    +
    58
    +    function isOpenInWeixin() {  // 判断当前网页是否在微信内置浏览器中打开
    59
    +        return /micromessenger/i.test(navigator.userAgent)
    60
    +    }
    61
    +
    62
    +    function getWeixinVersion() {
    63
    +        var ua = navigator.userAgent,
    64
    +            mt = ua.match(/micromessenger\/([\d.]+)/i)
    65
    +        return (mt ? mt[1] : '')
    66
    +    }
    67
    +
    68
    +    // This function checks whether Wechat is the appointed version or not
    69
    +    // Cmp: http://jsperf.com/regexp-test-vs-indexof-ignore-upper-and-lower
    70
    +    function isWeixinVersion(version) {
    71
    +        // return new RegExp('micromessenger/' + version , 'i').test(navigator.userAgent)
    72
    +        return navigator.userAgent.toLowerCase().indexOf('micromessenger/' + version) != -1
    73
    +    }
    74
    +
    75
    +    function hideOptionMenu() {
    76
    +        wxConfig.hide = true
    77
    +        fixedWxData()
    78
    +    }
    79
    +
    80
    +    function showOptionMenu() {
    81
    +        wxConfig.hide = false
    82
    +        fixedWxData()
    83
    +    }
    84
    +
    85
    +    function closeWindow() {
    86
    +        wxConfig.close = true
    87
    +        fixedWxData()
    88
    +    }
    89
    +
    90
    +    function wxReady(data) {
    91
    +        data = typeof data === 'object' ? data : JSON.parse(data)
    92
    +        wx.config({
    93
    +            debug: wxData.debug,
    94
    +            appId: data.appId,
    95
    +            timestamp: data.timestamp,
    96
    +            nonceStr: data.nonceStr,
    97
    +            signature: data.signature,
    98
    +            jsApiList: jsApiList
    99
    +        })
    100
    +
    101
    +        var callbacks = {
    102
    +            trigger: function (res) {
    103
    +                // alert('用户点击发送给朋友')
    104
    +                if (JSWE.wxTrigger) {JSWE.wxTrigger(res)}
    105
    +            },
    106
    +            success: function (res) {
    107
    +                // alert('已分享')
    108
    +                if (JSWE.wxSuccess) {JSWE.wxSuccess(res)}
    109
    +            },
    110
    +            cancel: function (res) {
    111
    +                // alert('已取消')
    112
    +                if (JSWE.wxCancel) {JSWE.wxCancel(res)}
    113
    +            },
    114
    +            fail: function (res) {
    115
    +                // alert(JSON.stringify(res))
    116
    +                if (JSWE.wxFail) {JSWE.wxFail(res)}
    117
    +            }
    118
    +        }, shareInfo = function(flag) {
    119
    +            var _share = {
    120
    +                title: flag ? wxData.title : (wxData.timeLine || wxData.desc),
    121
    +                link: wxData.link,
    122
    +                imgUrl: wxData.imgUrl,
    123
    +                trigger: callbacks.trigger,
    124
    +                success: callbacks.success,
    125
    +                cancel: callbacks.cancel,
    126
    +                fail: callbacks.fail
    127
    +            }
    128
    +            if (flag) _share.desc = wxData.desc
    129
    +            return _share
    130
    +        }, wxShareApi = function() {
    131
    +            // 2. 分享接口
    132
    +            // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
    133
    +            wx.onMenuShareAppMessage(shareInfo(1))
    134
    +            // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
    135
    +            wx.onMenuShareTimeline(shareInfo(0))
    136
    +            // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
    137
    +            wx.onMenuShareQQ(shareInfo(1))
    138
    +            // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
    139
    +            wx.onMenuShareWeibo(shareInfo(1))
    140
    +        }, wxMenuApi = function () {
    141
    +            // 8. 界面操作接口
    142
    +            // 8.1 隐藏右上角菜单
    143
    +            // 8.2 显示右上角菜单
    144
    +            if (wxConfig.hide) {wx.hideOptionMenu()} else {wx.showOptionMenu()}
    145
    +            // 8.7 关闭当前窗口
    146
    +            if (wxConfig.close) {wx.closeWindow()}
    147
    +        }, wxApi = function () {
    148
    +            wxShareApi()
    149
    +            wxMenuApi()
    150
    +        }
    151
    +
    152
    +        wx.ready(wxApi)
    153
    +
    154
    +        return wxApiFun = wxApi
    155
    +    }
    156
    +
    157
    +    if (isOpenInWeixin() || isOpenOnPC()) {
    158
    +        if ('undefined' !== typeof JSWE_CONF_UPDATE) JSWE_CONF_UPDATE(config)
    159
    +        $.ajax({
    160
    +            url: config.wxconfig,
    161
    +            type: 'get',
    162
    +            dataType: 'jsonp',
    163
    +            jsonpCallback: config.callback,
    164
    +            data: {
    165
    +                url: window.location.href.split('#')[0]
    166
    +            },
    167
    +            success: wxReady
    168
    +        })
    169
    +    }
    170
    +
    171
    +    function initWxData(data, flag) {
    172
    +        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
    173
    +        if (flag) fixedWxData()
    174
    +    }
    175
    +
    176
    +    function changeWxData(key, value, flag) {
    177
    +        if (key in falDwxDataata) {wxData[key] = value}
    178
    +        if (flag) fixedWxData()
    179
    +    }
    180
    +
    181
    +    function fixedWxData() {
    182
    +        if ('undefined' !== typeof wxApiFun) wxApiFun()
    183
    +    }
    184
    +
    185
    +    // 5 图片接口
    186
    +    // 5.1 拍照、本地选图
    187
    +    var images = {
    188
    +        localIds: [],
    189
    +        serverIds: []
    190
    +    };
    191
    +    function chooseImage(count, directUpload, isShowProgressTips) {
    192
    +        if ('undefined' === typeof count) {count = 9}
    193
    +        if ('undefined' === typeof directUpload) {directUpload = false}
    194
    +        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
    195
    +        wx.chooseImage({
    196
    +            count: count, // 默认9
    197
    +            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
    198
    +            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
    199
    +            success: function (res) {
    200
    +                var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
    201
    +                images.localIds = localIds;
    202
    +                // 判断是否直接上传
    203
    +                if (directUpload) {setTimeout(uploadImages(localIds, isShowProgressTips), 100)}
    204
    +                // 拍照、本地选图成功后的回调函数
    205
    +                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res)}
    206
    +            }
    207
    +        });
    208
    +    }
    209
    +
    210
    +    // 5.3 上传图片
    211
    +    function uploadImage(localId, isShowProgressTips) {
    212
    +        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
    213
    +        wx.uploadImage({
    214
    +            localId: localId, // 需要上传的图片的本地ID,由chooseImage接口获得
    215
    +            isShowProgressTips: 1, // 默认为1,显示进度提示
    216
    +            success: function (res) {
    217
    +                var serverId = res.serverId; // 返回图片的服务器端ID
    218
    +                images.serverIds.push(serverId);
    219
    +                // 上传图片成功后的回调函数
    220
    +                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res)}
    221
    +            }
    222
    +        });
    223
    +    }
    224
    +
    225
    +    function uploadImages(localIds, isShowProgressTips) {
    226
    +        if ('undefined' === typeof localIds) {localIds = images.localIds}
    227
    +        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
    228
    +        images.serverIds = [];
    229
    +        for (var index in localIds) {uploadImage(localIds[index], isShowProgressTips)}
    230
    +    }
    231
    +
    232
    +    // 10 微信支付接口
    233
    +    // 10.1 发起一个支付请求
    234
    +    function chooseWXPay(wxpay_params) {
    235
    +        wx.chooseWXPay({
    236
    +            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    237
    +            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
    238
    +            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    239
    +            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    240
    +            paySign: wxpay_params.paySign, // 支付签名
    241
    +            success: function (res) {
    242
    +                // 支付成功后的回调函数
    243
    +                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
    244
    +            }
    245
    +        })
    246
    +    }
    247
    +
    248
    +    // xx 微信原生企业红包接口
    249
    +    // xx.1 发起一个发送原生企业红包请求
    250
    +    function openEnterpriseRedPacket(wxredpack_params) {
    251
    +        wx.openEnterpriseRedPacket({
    252
    +            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    253
    +            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
    254
    +            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    255
    +            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    256
    +            paySign: wxredpack_params.paySign, // 红包签名
    257
    +            success: function (res) {
    258
    +                // 发送原生企业红包成功后的回调函数
    259
    +                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
    260
    +            }
    261
    +        })
    262
    +    }
    263
    +
    264
    +    var v = {
    265
    +        version: '1.0.5',
    266
    +
    267
    +        // Basic Vars
    268
    +        config: config,
    269
    +        wxData: wxData,
    270
    +        jsApiList: jsApiList,
    271
    +
    272
    +        // Weixin Function
    273
    +        isOpenInWeixin: isOpenInWeixin,
    274
    +        getWeixinVersion: getWeixinVersion,
    275
    +        isWeixinVersion: isWeixinVersion,
    276
    +
    277
    +        // Menu Function
    278
    +        hideOptionMenu: hideOptionMenu,
    279
    +        showOptionMenu: showOptionMenu,
    280
    +        closeWindow: closeWindow,
    281
    +
    282
    +        // Share Function
    283
    +        initWxData: initWxData,
    284
    +        changeWxData: changeWxData,
    285
    +        fixedWxData: fixedWxData,
    286
    +
    287
    +        // Image Function
    288
    +        images: images,
    289
    +        chooseImage: chooseImage,
    290
    +        uploadImage: uploadImage,
    291
    +        uploadImages: uploadImages,
    292
    +
    293
    +        // Pay Function
    294
    +        chooseWXPay: chooseWXPay,
    295
    +
    296
    +        // EnterpriseRedPacket Function
    297
    +        openEnterpriseRedPacket: openEnterpriseRedPacket
    298
    +    }
    299
    +    e.JSWE = e.V = v
    300
    +})(window)

    + 33 - 0
    tamron/urls.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +"""tamron URL Configuration
    4
    +
    5
    +The `urlpatterns` list routes URLs to views. For more information please see:
    6
    +    https://docs.djangoproject.com/en/1.8/topics/http/urls/
    7
    +Examples:
    8
    +Function views
    9
    +    1. Add an import:  from my_app import views
    10
    +    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
    11
    +Class-based views
    12
    +    1. Add an import:  from other_app.views import Home
    13
    +    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    14
    +Including another URLconf
    15
    +    1. Add an import:  from blog import urls as blog_urls
    16
    +    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
    17
    +"""
    18
    +from django.conf.urls import include, url
    19
    +from django.contrib import admin
    20
    +
    21
    +from page import info_views, oauth_views, sale_views
    22
    +
    23
    +
    24
    +urlpatterns = [
    25
    +    url(r'^admin/', include(admin.site.urls)),
    26
    +    url(r'^api/', include('api.urls', namespace='api')),
    27
    +]
    28
    +
    29
    +urlpatterns += [
    30
    +    url(r'^page/clerk$', oauth_views.clerk_oauth, name='clerk_oauth'),  # 店员授权页面
    31
    +    url(r'^page/clerk/sale$', sale_views.clerk_sale_oauth, name='clerk_sale_oauth'),  # 店员销售授权页面
    32
    +    url(r'^page/clerk/info$', info_views.clerk_info_oauth, name='clerk_info_oauth'),  # 店员信息授权页面
    33
    +]

    BIN
    tamron/urls.pyc


    + 2 - 0
    tamron/uwsgi.bak/shutdown.sh

    @@ -0,0 +1,2 @@
    1
    +killall -9 uwsgi
    2
    +echo "2敏加油~~~!!!↖(^ω^)↗"

    + 2 - 0
    tamron/uwsgi.bak/startup.sh

    @@ -0,0 +1,2 @@
    1
    +nohup uwsgi --ini pai2.ini &>pai2.log &
    2
    +echo "Start Success !!!"

    + 27 - 0
    tamron/uwsgi.bak/tamron.ini

    @@ -0,0 +1,27 @@
    1
    +# tamron_uwsgi.ini file
    2
    +[uwsgi]
    3
    +
    4
    +# Django-related settings
    5
    +# the base directory (full path)
    6
    +chdir           = /home/paiai/work/tamron
    7
    +# Django's wsgi file
    8
    +module          = tamron.wsgi
    9
    +# the virtualenv (full path)
    10
    +# home            = /path/to/virtualenv
    11
    +
    12
    +# process-related settings
    13
    +# master
    14
    +master          = true
    15
    +# maximum number of worker processes
    16
    +processes       = 10
    17
    +# the socket (use the full path to be safe
    18
    +socket          = /home/paiai/work/tamron/tamron/uwsgi/tamron.sock
    19
    +# ... with appropriate permissions - may be needed
    20
    +chmod-socket    = 777
    21
    +# clear environment on exit
    22
    +vacuum          = true
    23
    +
    24
    +# 11: Resource temporarily unavailable
    25
    +reload-mercy    = 64
    26
    +max-requests    = 8192
    27
    +listen          = 4096

    + 35 - 0
    tamron/uwsgi.bak/tamron_nginx.conf

    @@ -0,0 +1,35 @@
    1
    +# tamron_nginx.conf
    2
    +
    3
    +# the upstream component nginx needs to connect to
    4
    +upstream pai2 {
    5
    +    # server unix:///home/paiai/work/tamron/tamron/uwsgi/tamron.sock; # for a file socket
    6
    +    server 127.0.0.1:8888; # for a web port socket (we'll use this first)
    7
    +}
    8
    +
    9
    +# configuration of the server
    10
    +server {
    11
    +    # the port your site will be served on
    12
    +    listen      80;
    13
    +    # the domain name it will serve for
    14
    +    server_name .tamron.xfoto.com.cn; # substitute your machine's IP address or FQDN
    15
    +    charset     utf-8;
    16
    +
    17
    +    # max upload size
    18
    +    client_max_body_size 75M;   # adjust to taste
    19
    +
    20
    +    # Django media
    21
    +    location /media  {
    22
    +        alias /home/paiai/work/tamron/media;  # your Django project's media files - amend as required
    23
    +    }
    24
    +
    25
    +    location /static {
    26
    +        alias /home/paiai/work/tamron/collect_static; # your Django project's static files - amend as required
    27
    +    }
    28
    +
    29
    +    # Finally, send all non-media requests to the Django server.
    30
    +    location / {
    31
    +        # uwsgi_pass  tamron;
    32
    +        proxy_pass  http://tamron;
    33
    +        include     /home/paiai/work/tamron/tamron/uwsgi/uwsgi_params; # the uwsgi_params file you installed
    34
    +    }
    35
    +}

    + 15 - 0
    tamron/uwsgi.bak/uwsgi_params

    @@ -0,0 +1,15 @@
    1
    +uwsgi_param	QUERY_STRING		$query_string;
    2
    +uwsgi_param	REQUEST_METHOD		$request_method;
    3
    +uwsgi_param	CONTENT_TYPE		$content_type;
    4
    +uwsgi_param	CONTENT_LENGTH		$content_length;
    5
    +
    6
    +uwsgi_param	REQUEST_URI		$request_uri;
    7
    +uwsgi_param	PATH_INFO		$document_uri;
    8
    +uwsgi_param	DOCUMENT_ROOT		$document_root;
    9
    +uwsgi_param	SERVER_PROTOCOL		$server_protocol;
    10
    +uwsgi_param	UWSGI_SCHEME		$scheme;
    11
    +
    12
    +uwsgi_param	REMOTE_ADDR		$remote_addr;
    13
    +uwsgi_param	REMOTE_PORT		$remote_port;
    14
    +uwsgi_param	SERVER_PORT		$server_port;
    15
    +uwsgi_param	SERVER_NAME		$server_name;

    + 17 - 0
    tamron/wsgi.py

    @@ -0,0 +1,17 @@
    1
    +"""
    2
    +WSGI config for tamron project.
    3
    +
    4
    +It exposes the WSGI callable as a module-level variable named ``application``.
    5
    +
    6
    +For more information on this file, see
    7
    +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
    8
    +"""
    9
    +
    10
    +import os
    11
    +
    12
    +from django.core.wsgi import get_wsgi_application
    13
    +
    14
    +
    15
    +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
    16
    +
    17
    +application = get_wsgi_application()

    BIN
    tamron/wsgi.pyc


    + 0 - 0
    utils/__init__.py


    BIN
    utils/__init__.pyc


    + 0 - 0
    utils/error/__init__.py


    BIN
    utils/error/__init__.pyc


    + 62 - 0
    utils/error/errno_utils.py

    @@ -0,0 +1,62 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from StatusCode import BaseStatusCode, StatusCodeField
    4
    +
    5
    +
    6
    +class FranchiserStatusCode(BaseStatusCode):
    7
    +    """ 店员相关错误码 4001xx """
    8
    +    CHISER_NOT_FOUND = StatusCodeField(400001, 'Chiser Not Found', description=u'经销商不存在')
    9
    +
    10
    +
    11
    +class SaleclerkStatusCode(BaseStatusCode):
    12
    +    """ 店员相关错误码 4001xx """
    13
    +    CLERK_NOT_FOUND = StatusCodeField(400101, 'Clerk Not Found', description=u'店员不存在')
    14
    +    # 手机号
    15
    +    CLERK_PHONE_ALREADY_EXISTS = StatusCodeField(400105, 'Clerk Phone Already Exists', description=u'手机号已经存在')
    16
    +    # 状态
    17
    +    CLERK_ALREADY_NOT_UNVERIFIED = StatusCodeField(400110, 'Clerk Already Not Unverified', description=u'店员帐号已激活')
    18
    +    CLERK_NOT_ACTIVATED = StatusCodeField(400115, 'Clerk Not Activated', description=u'店员帐号未激活')
    19
    +
    20
    +
    21
    +class ProductModelStatusCode(BaseStatusCode):
    22
    +    """ 型号相关错误码 4010xx """
    23
    +    MODEL_NOT_FOUND = StatusCodeField(401001, 'Model Not Found', description=u'型号不存在')
    24
    +
    25
    +
    26
    +class ProductStatusCode(BaseStatusCode):
    27
    +    """ 产品相关错误码 4020xx """
    28
    +    PRODUCT_NOT_FOUND = StatusCodeField(402001, 'Product Not Found', description=u'产品不存在')
    29
    +    # 状态
    30
    +    PRODUCT_HAS_USED = StatusCodeField(402011, 'Product Has Used', description=u'产品已使用')
    31
    +
    32
    +
    33
    +class OrderStatusCode(BaseStatusCode):
    34
    +    """ 订单/支付相关错误码 4040xx """
    35
    +    WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'WX Unified Order Fail', description=u'微信统一下单失败')
    36
    +    WX_ORDER_NOT_FOUND = StatusCodeField(404001, 'WX Order Not Found', description=u'订单不存在')
    37
    +    WX_ORDER_NOT_PAY = StatusCodeField(404002, 'WX Order Not Pay', description=u'订单未支付')
    38
    +    WX_ORDER_PAYING = StatusCodeField(404003, 'WX Order Paying', description=u'订单支付中')
    39
    +    WX_ORDER_PAY_FAIL = StatusCodeField(404009, 'WX Order Pay Fail', description=u'微信支付失败')
    40
    +    SIGN_CHECK_FAIL = StatusCodeField(404010, 'Sign Check Fail', description=u'签名校验失败')
    41
    +    FEE_CHECK_FAIL = StatusCodeField(404011, 'FEE Check Fail', description=u'金额校验失败')
    42
    +    NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'无详情权限')
    43
    +    WX_ORDER_PAID_ALREADY_EXISTS = StatusCodeField(404020, 'WX Order Paid Already Exists', description=u'照片已购买')
    44
    +
    45
    +
    46
    +class PayStatusCode(BaseStatusCode):
    47
    +    """ 支付相关错误码 4041xx """
    48
    +
    49
    +
    50
    +class WithdrawStatusCode(BaseStatusCode):
    51
    +    """ 提现相关错误码 4042xx """
    52
    +    BALANCE_NOT_ENOUGH = StatusCodeField(404200, 'Balance Not Enough', description=u'提现金额不足')
    53
    +
    54
    +
    55
    +class MessageStatusCode(BaseStatusCode):
    56
    +    """ 消息相关错误码 4090xx """
    57
    +    MESSAGE_NOT_FOUND = StatusCodeField(409001, 'Message Not Found', description=u'消息不存在')
    58
    +
    59
    +
    60
    +class TokenStatusCode(BaseStatusCode):
    61
    +    """ 票据相关错误码 4090xx """
    62
    +    TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在')

    BIN
    utils/error/errno_utils.pyc


    + 18 - 0
    utils/error/response_utils.py

    @@ -0,0 +1,18 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.http import JsonResponse
    4
    +from StatusCode import StatusCodeField
    5
    +
    6
    +
    7
    +def response_data(status_code=200, message=None, description=None, data={}, **kwargs):
    8
    +    return dict({
    9
    +        'status': status_code,
    10
    +        'message': message,
    11
    +        'description': description,
    12
    +        'data': data,
    13
    +    }, **kwargs)
    14
    +
    15
    +
    16
    +def response(status_code=200, message=None, description=None, data={}, **kwargs):
    17
    +    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
    18
    +    return JsonResponse(response_data(status_code, message, description, data, **kwargs), safe=False)

    BIN
    utils/error/response_utils.pyc


    + 0 - 0
    utils/redis/__init__.py


    BIN
    utils/redis/__init__.pyc


    + 6 - 0
    utils/redis/connect.py

    @@ -0,0 +1,6 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.conf import settings
    4
    +
    5
    +
    6
    +r = settings.REDIS_CACHE

    BIN
    utils/redis/connect.pyc


    + 68 - 0
    utils/redis/rkeys.py

    @@ -0,0 +1,68 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +# 唯一标识相关
    4
    +UUID_LIST = 'uuid:list'  # List,唯一标识列表
    5
    +
    6
    +# 用户相关
    7
    +PROFILE_INFO = 'profile:info:%s'  # STRING,用户信息,user_id
    8
    +
    9
    +# 导游相关
    10
    +TOUR_GUIDE_GROUP_GEO_INFO = 'tour:guide:group:geo:info:%s'  # ZSET,旅游团地理位置信息,group_id
    11
    +TOUR_GUIDE_GROUP_GEO_SUBMIT_DT = 'tour:guide:group:geo:submit:dt:%s'  # ZSET,旅游团地理位置最后上传时间,group_id
    12
    +TOUR_GUIDE_GROUP_CUR_SESSION = 'tour:guide:group:cur:session:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
    13
    +TOUR_GUIDE_GROUP_CUR_GATHER_INFO = 'tour:guide:group:cur:gather:info:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
    14
    +TOUR_GUIDE_GROUP_USER_GEO_LIST = 'tour:guide:group:user:geo:list:%s:%s:%s'  # LIST,旅游团当前用户地理位置列表,group_id、session_id、user_id
    15
    +
    16
    +TOUR_GUIDE_GROUP_USER_OWN = 'tour:guide:group:user:own:%s'  # STRING,导游当前拥有的旅行团,user_id,导游创建旅行团的时候更新
    17
    +TOUR_GUIDE_GROUP_USER_BELONG = 'tour:guide:group:user:belong:%s'  # STRING,用户当前所属旅行团,user_id,用户加入旅行团的时候更新
    18
    +
    19
    +# 群组相关
    20
    +GROUP_INFO = 'group:info:%s'  # STRING,群组信息,group_id
    21
    +
    22
    +# 群组用户相关
    23
    +GROUP_USERS_INFO = 'group:users:info:%s'  # STRING,群组用户信息,group_id
    24
    +GROUP_USERS_KV_INFO = 'group:users:kv:info:%s'  # STRING,群组用户信息,group_id
    25
    +GROUP_USERS_APPLYING_SET = 'group:users:applying:set:%s'  # SET,群组用户申请集合,group_id
    26
    +GROUP_USERS_PASSED_SET = 'group:users:passed:set:%s'  # SET,群组用户通过集合,group_id
    27
    +GROUP_USERS_REFUSED_SET = 'group:users:refused:set:%s'  # SET,群组用户拒绝集合,group_id
    28
    +GROUP_USERS_DELETED_SET = 'group:users:deleted:set:%s'  # SET,群组用户移除集合,group_id
    29
    +GROUP_USERS_QUIT_SET = 'group:users:quit:set:%s'  # SET,群组用户退出集合,group_id
    30
    +
    31
    +# 群组照片相关
    32
    +GROUP_PHOTO_DATA = 'group:photo:data:%s'  # STRING,群组数据记录,group_id
    33
    +GROUP_PHOTO_THUMB_UP = 'group:photo:thumb:up:%s:%s'  # STRING,群组照片用户点赞记录,photo_id、user_id
    34
    +GROUP_PHOTO_COMMENT_LIST = 'group:photo:comment:list:%s'  # STRING,群组照片用户评论列表,photo_id
    35
    +GROUP_PHOTO_THUMB_UP_LIST = 'group:photo:thumb:up:list:%s'  # STRING,群组照片用户点赞列表,photo_id
    36
    +GROUP_PHOTO_WATCHER_SET = 'group:photo:watcher:set:%s'  # SET,群组照片用户关注集合,photo_id,关注即评论点赞
    37
    +GROUP_LAST_PHOTO_PK = 'group:last:photo:pk:%s'  # STRING,群组最后一张照片PK,group_id
    38
    +
    39
    +# 摄影师照片相关
    40
    +LENSMAN_PHOTO_ORDER_RECORD = 'lensman:photo:order:record:%s:%s'  # STRING,摄影师照片购买记录,photo_id、user_id
    41
    +
    42
    +# 摄影师简报相关
    43
    +# 收入
    44
    +TOTAL_INCOME = 'total:income:%s:%s'  # STRING,总收入,user_id、photo_type
    45
    +WEEK_INCOME = 'week:income:%s:%s:%s'  # STRING,周收入,user_id、photo_type、Week.thisweek().isoformat()
    46
    +TODAY_INCOME = 'today:income:%s:%s:%s'  # STRING,日收入,user_id、photo_type、tc.local_string(format='%Y%m%d')
    47
    +# 上传
    48
    +TODAY_UPLOAD_PHOTO_AMOUNT = 'today:upload:photo:amount:%s:%s'  # STRING,日上传照片数量,user_id、tc.local_string(format='%Y%m%d')
    49
    +# 售出
    50
    +WEEK_SOLD = 'week:sold:%s:%s:%s'  # STRING,周售出,user_id、photo_type、Week.thisweek().isoformat()
    51
    +
    52
    +# 摄影师定价相关
    53
    +LENSMAN_PHOTO_PRICE_FIXED = 'lensman:photo:price:fixed:%s'  # STRING,摄影师照片定价(单位:分),user_id
    54
    +
    55
    +# 系统消息相关
    56
    +SYSTEM_MESSAGE_READ_INFO = 'system:message:read:info:%s'  # STRING,系统消息读取信息,user_id
    57
    +SYSTEM_MESSAGE_DELETED_INFO = 'system:message:deleted:info:%s'  # STRING,系统消息删除信息,user_id
    58
    +
    59
    +# 游客入口相关
    60
    +GUEST_ENTRANCE_CONTROL_INFO = 'guest:entrance:control:info:%s'  # STRING,游客入口控制信息,src
    61
    +
    62
    +# APP 相关
    63
    +LATEST_APP_INFO = 'latest:app:info:%s'  # STRING,最新 APP 信息,src
    64
    +APP_SETTINGS_INFO = 'app:settings:info:%s:%s:%s'  # STRING,APP 设置信息,platform、channel、version
    65
    +APP_PATCH_INFO = 'app:patch:info:%s:%s:%s'  # STRING,APP 补丁信息,platform、version、src
    66
    +
    67
    +# BOX 相关
    68
    +BOX_PROGRAM_VERSION_INFO = 'box:program:version:info'  # STRING,BOX 程序版本信息

    kodo - Gogs: Go Git Service

    Aucune description

    huangqimin: 3d0d214667 :sparkles: Member Infos 6 ans auparavant
    ..
    simditor 3d0d214667 :sparkles: Member Infos 6 ans auparavant